reformat
This commit is contained in:
parent
ac6060fe0d
commit
d929aa6652
|
@ -3,10 +3,13 @@ import com.android.tools.profgen.ArtProfileSerializer
|
||||||
import com.android.tools.profgen.DexFile
|
import com.android.tools.profgen.DexFile
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
|
id 'java'
|
||||||
|
id 'maven-publish'
|
||||||
id "com.android.application"
|
id "com.android.application"
|
||||||
id "kotlin-android"
|
id "kotlin-android"
|
||||||
id "kotlin-kapt"
|
id "kotlin-kapt"
|
||||||
id "kotlin-parcelize"
|
id "kotlin-parcelize"
|
||||||
|
id("org.openrewrite.rewrite") version("5.37.0")
|
||||||
id "checkstyle"
|
id "checkstyle"
|
||||||
id "org.sonarqube" version "3.5.0.2730"
|
id "org.sonarqube" version "3.5.0.2730"
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,14 +4,17 @@ import android.app.Application;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.core.app.NotificationChannelCompat;
|
import androidx.core.app.NotificationChannelCompat;
|
||||||
import androidx.core.app.NotificationManagerCompat;
|
import androidx.core.app.NotificationManagerCompat;
|
||||||
import androidx.preference.PreferenceManager;
|
import androidx.preference.PreferenceManager;
|
||||||
|
|
||||||
import com.jakewharton.processphoenix.ProcessPhoenix;
|
import com.jakewharton.processphoenix.ProcessPhoenix;
|
||||||
|
import io.reactivex.rxjava3.exceptions.CompositeException;
|
||||||
|
import io.reactivex.rxjava3.exceptions.MissingBackpressureException;
|
||||||
|
import io.reactivex.rxjava3.exceptions.OnErrorNotImplementedException;
|
||||||
|
import io.reactivex.rxjava3.exceptions.UndeliverableException;
|
||||||
|
import io.reactivex.rxjava3.functions.Consumer;
|
||||||
|
import io.reactivex.rxjava3.plugins.RxJavaPlugins;
|
||||||
import org.acra.ACRA;
|
import org.acra.ACRA;
|
||||||
import org.acra.config.CoreConfigurationBuilder;
|
import org.acra.config.CoreConfigurationBuilder;
|
||||||
import org.schabi.newpipe.error.ReCaptchaActivity;
|
import org.schabi.newpipe.error.ReCaptchaActivity;
|
||||||
|
@ -30,13 +33,6 @@ import java.net.SocketException;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
import io.reactivex.rxjava3.exceptions.CompositeException;
|
|
||||||
import io.reactivex.rxjava3.exceptions.MissingBackpressureException;
|
|
||||||
import io.reactivex.rxjava3.exceptions.OnErrorNotImplementedException;
|
|
||||||
import io.reactivex.rxjava3.exceptions.UndeliverableException;
|
|
||||||
import io.reactivex.rxjava3.functions.Consumer;
|
|
||||||
import io.reactivex.rxjava3.plugins.RxJavaPlugins;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (C) Hans-Christoph Steiner 2016 <hans@eds.org>
|
* Copyright (C) Hans-Christoph Steiner 2016 <hans@eds.org>
|
||||||
* App.java is part of NewPipe.
|
* App.java is part of NewPipe.
|
||||||
|
@ -87,8 +83,8 @@ public class App extends Application {
|
||||||
NewPipeSettings.initSettings(this);
|
NewPipeSettings.initSettings(this);
|
||||||
|
|
||||||
NewPipe.init(getDownloader(),
|
NewPipe.init(getDownloader(),
|
||||||
Localization.getPreferredLocalization(this),
|
Localization.getPreferredLocalization(this),
|
||||||
Localization.getPreferredContentCountry(this));
|
Localization.getPreferredContentCountry(this));
|
||||||
Localization.initPrettyTime(Localization.resolvePrettyTime(getApplicationContext()));
|
Localization.initPrettyTime(Localization.resolvePrettyTime(getApplicationContext()));
|
||||||
|
|
||||||
StateSaver.init(this);
|
StateSaver.init(this);
|
||||||
|
|
|
@ -4,19 +4,17 @@ import android.content.Context;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.appcompat.app.AppCompatActivity;
|
import androidx.appcompat.app.AppCompatActivity;
|
||||||
import androidx.fragment.app.Fragment;
|
import androidx.fragment.app.Fragment;
|
||||||
import androidx.fragment.app.FragmentManager;
|
import androidx.fragment.app.FragmentManager;
|
||||||
|
|
||||||
import icepick.Icepick;
|
import icepick.Icepick;
|
||||||
import icepick.State;
|
import icepick.State;
|
||||||
import leakcanary.AppWatcher;
|
import leakcanary.AppWatcher;
|
||||||
|
|
||||||
public abstract class BaseFragment extends Fragment {
|
public abstract class BaseFragment extends Fragment {
|
||||||
protected final String TAG = getClass().getSimpleName() + "@" + Integer.toHexString(hashCode());
|
|
||||||
protected static final boolean DEBUG = MainActivity.DEBUG;
|
protected static final boolean DEBUG = MainActivity.DEBUG;
|
||||||
|
protected final String TAG = getClass().getSimpleName() + "@" + Integer.toHexString(hashCode());
|
||||||
protected AppCompatActivity activity;
|
protected AppCompatActivity activity;
|
||||||
//These values are used for controlling fragments when they are part of the frontpage
|
//These values are used for controlling fragments when they are part of the frontpage
|
||||||
@State
|
@State
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
package org.schabi.newpipe;
|
package org.schabi.newpipe;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.preference.PreferenceManager;
|
import androidx.preference.PreferenceManager;
|
||||||
|
import okhttp3.OkHttpClient;
|
||||||
|
import okhttp3.RequestBody;
|
||||||
|
import okhttp3.ResponseBody;
|
||||||
import org.schabi.newpipe.error.ReCaptchaActivity;
|
import org.schabi.newpipe.error.ReCaptchaActivity;
|
||||||
import org.schabi.newpipe.extractor.downloader.Downloader;
|
import org.schabi.newpipe.extractor.downloader.Downloader;
|
||||||
import org.schabi.newpipe.extractor.downloader.Request;
|
import org.schabi.newpipe.extractor.downloader.Request;
|
||||||
|
@ -14,19 +15,11 @@ import org.schabi.newpipe.extractor.exceptions.ReCaptchaException;
|
||||||
import org.schabi.newpipe.util.InfoCache;
|
import org.schabi.newpipe.util.InfoCache;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Arrays;
|
import java.util.*;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import okhttp3.OkHttpClient;
|
|
||||||
import okhttp3.RequestBody;
|
|
||||||
import okhttp3.ResponseBody;
|
|
||||||
|
|
||||||
public final class DownloaderImpl extends Downloader {
|
public final class DownloaderImpl extends Downloader {
|
||||||
public static final String USER_AGENT =
|
public static final String USER_AGENT =
|
||||||
"Mozilla/5.0 (Windows NT 10.0; rv:91.0) Gecko/20100101 Firefox/91.0";
|
"Mozilla/5.0 (Windows NT 10.0; rv:91.0) Gecko/20100101 Firefox/91.0";
|
||||||
|
|
|
@ -4,7 +4,6 @@ import android.annotation.SuppressLint;
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
|
||||||
import org.schabi.newpipe.util.NavigationHelper;
|
import org.schabi.newpipe.util.NavigationHelper;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -20,29 +20,17 @@
|
||||||
|
|
||||||
package org.schabi.newpipe;
|
package org.schabi.newpipe;
|
||||||
|
|
||||||
import static org.schabi.newpipe.util.Localization.assureCorrectAppLanguage;
|
import android.content.*;
|
||||||
|
|
||||||
import android.content.BroadcastReceiver;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.content.IntentFilter;
|
|
||||||
import android.content.SharedPreferences;
|
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.Looper;
|
import android.os.Looper;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.KeyEvent;
|
import android.view.*;
|
||||||
import android.view.LayoutInflater;
|
|
||||||
import android.view.Menu;
|
|
||||||
import android.view.MenuItem;
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.ViewGroup;
|
|
||||||
import android.widget.AdapterView;
|
import android.widget.AdapterView;
|
||||||
import android.widget.ArrayAdapter;
|
import android.widget.ArrayAdapter;
|
||||||
import android.widget.FrameLayout;
|
import android.widget.FrameLayout;
|
||||||
import android.widget.Spinner;
|
import android.widget.Spinner;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.appcompat.app.ActionBar;
|
import androidx.appcompat.app.ActionBar;
|
||||||
import androidx.appcompat.app.ActionBarDrawerToggle;
|
import androidx.appcompat.app.ActionBarDrawerToggle;
|
||||||
|
@ -53,14 +41,8 @@ import androidx.drawerlayout.widget.DrawerLayout;
|
||||||
import androidx.fragment.app.Fragment;
|
import androidx.fragment.app.Fragment;
|
||||||
import androidx.fragment.app.FragmentManager;
|
import androidx.fragment.app.FragmentManager;
|
||||||
import androidx.preference.PreferenceManager;
|
import androidx.preference.PreferenceManager;
|
||||||
|
|
||||||
import com.google.android.material.bottomsheet.BottomSheetBehavior;
|
import com.google.android.material.bottomsheet.BottomSheetBehavior;
|
||||||
|
import org.schabi.newpipe.databinding.*;
|
||||||
import org.schabi.newpipe.databinding.ActivityMainBinding;
|
|
||||||
import org.schabi.newpipe.databinding.DrawerHeaderBinding;
|
|
||||||
import org.schabi.newpipe.databinding.DrawerLayoutBinding;
|
|
||||||
import org.schabi.newpipe.databinding.InstanceSpinnerLayoutBinding;
|
|
||||||
import org.schabi.newpipe.databinding.ToolbarLayoutBinding;
|
|
||||||
import org.schabi.newpipe.error.ErrorUtil;
|
import org.schabi.newpipe.error.ErrorUtil;
|
||||||
import org.schabi.newpipe.extractor.NewPipe;
|
import org.schabi.newpipe.extractor.NewPipe;
|
||||||
import org.schabi.newpipe.extractor.StreamingService;
|
import org.schabi.newpipe.extractor.StreamingService;
|
||||||
|
@ -75,39 +57,19 @@ import org.schabi.newpipe.player.Player;
|
||||||
import org.schabi.newpipe.player.event.OnKeyDownListener;
|
import org.schabi.newpipe.player.event.OnKeyDownListener;
|
||||||
import org.schabi.newpipe.player.helper.PlayerHolder;
|
import org.schabi.newpipe.player.helper.PlayerHolder;
|
||||||
import org.schabi.newpipe.player.playqueue.PlayQueue;
|
import org.schabi.newpipe.player.playqueue.PlayQueue;
|
||||||
import org.schabi.newpipe.util.Constants;
|
import org.schabi.newpipe.util.*;
|
||||||
import org.schabi.newpipe.util.DeviceUtils;
|
|
||||||
import org.schabi.newpipe.util.KioskTranslator;
|
|
||||||
import org.schabi.newpipe.util.Localization;
|
|
||||||
import org.schabi.newpipe.util.NavigationHelper;
|
|
||||||
import org.schabi.newpipe.util.PeertubeHelper;
|
|
||||||
import org.schabi.newpipe.util.PermissionHelper;
|
|
||||||
import org.schabi.newpipe.util.SerializedCache;
|
|
||||||
import org.schabi.newpipe.util.ServiceHelper;
|
|
||||||
import org.schabi.newpipe.util.StateSaver;
|
|
||||||
import org.schabi.newpipe.util.ThemeHelper;
|
|
||||||
import org.schabi.newpipe.views.FocusOverlayView;
|
import org.schabi.newpipe.views.FocusOverlayView;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
|
import static org.schabi.newpipe.util.Localization.assureCorrectAppLanguage;
|
||||||
|
|
||||||
public class MainActivity extends AppCompatActivity {
|
public class MainActivity extends AppCompatActivity {
|
||||||
private static final String TAG = "MainActivity";
|
|
||||||
@SuppressWarnings("ConstantConditions")
|
@SuppressWarnings("ConstantConditions")
|
||||||
public static final boolean DEBUG = !BuildConfig.BUILD_TYPE.equals("release");
|
public static final boolean DEBUG = !BuildConfig.BUILD_TYPE.equals("release");
|
||||||
|
private static final String TAG = "MainActivity";
|
||||||
private ActivityMainBinding mainBinding;
|
|
||||||
private DrawerHeaderBinding drawerHeaderBinding;
|
|
||||||
private DrawerLayoutBinding drawerLayoutBinding;
|
|
||||||
private ToolbarLayoutBinding toolbarLayoutBinding;
|
|
||||||
|
|
||||||
private ActionBarDrawerToggle toggle;
|
|
||||||
|
|
||||||
private boolean servicesShown = false;
|
|
||||||
|
|
||||||
private BroadcastReceiver broadcastReceiver;
|
|
||||||
|
|
||||||
private static final int ITEM_ID_SUBSCRIPTIONS = -1;
|
private static final int ITEM_ID_SUBSCRIPTIONS = -1;
|
||||||
private static final int ITEM_ID_FEED = -2;
|
private static final int ITEM_ID_FEED = -2;
|
||||||
private static final int ITEM_ID_BOOKMARKS = -3;
|
private static final int ITEM_ID_BOOKMARKS = -3;
|
||||||
|
@ -115,8 +77,14 @@ public class MainActivity extends AppCompatActivity {
|
||||||
private static final int ITEM_ID_HISTORY = -5;
|
private static final int ITEM_ID_HISTORY = -5;
|
||||||
private static final int ITEM_ID_SETTINGS = 0;
|
private static final int ITEM_ID_SETTINGS = 0;
|
||||||
private static final int ITEM_ID_ABOUT = 1;
|
private static final int ITEM_ID_ABOUT = 1;
|
||||||
|
|
||||||
private static final int ORDER = 0;
|
private static final int ORDER = 0;
|
||||||
|
private ActivityMainBinding mainBinding;
|
||||||
|
private DrawerHeaderBinding drawerHeaderBinding;
|
||||||
|
private DrawerLayoutBinding drawerLayoutBinding;
|
||||||
|
private ToolbarLayoutBinding toolbarLayoutBinding;
|
||||||
|
private ActionBarDrawerToggle toggle;
|
||||||
|
private boolean servicesShown = false;
|
||||||
|
private BroadcastReceiver broadcastReceiver;
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
// Activity's LifeCycle
|
// Activity's LifeCycle
|
||||||
|
|
|
@ -1,20 +1,14 @@
|
||||||
package org.schabi.newpipe;
|
package org.schabi.newpipe;
|
||||||
|
|
||||||
import static org.schabi.newpipe.database.AppDatabase.DATABASE_NAME;
|
|
||||||
import static org.schabi.newpipe.database.Migrations.MIGRATION_1_2;
|
|
||||||
import static org.schabi.newpipe.database.Migrations.MIGRATION_2_3;
|
|
||||||
import static org.schabi.newpipe.database.Migrations.MIGRATION_3_4;
|
|
||||||
import static org.schabi.newpipe.database.Migrations.MIGRATION_4_5;
|
|
||||||
import static org.schabi.newpipe.database.Migrations.MIGRATION_5_6;
|
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.room.Room;
|
import androidx.room.Room;
|
||||||
|
|
||||||
import org.schabi.newpipe.database.AppDatabase;
|
import org.schabi.newpipe.database.AppDatabase;
|
||||||
|
|
||||||
|
import static org.schabi.newpipe.database.AppDatabase.DATABASE_NAME;
|
||||||
|
import static org.schabi.newpipe.database.Migrations.*;
|
||||||
|
|
||||||
public final class NewPipeDatabase {
|
public final class NewPipeDatabase {
|
||||||
private static volatile AppDatabase databaseInstance;
|
private static volatile AppDatabase databaseInstance;
|
||||||
|
|
||||||
|
|
|
@ -1,15 +1,10 @@
|
||||||
package org.schabi.newpipe;
|
package org.schabi.newpipe;
|
||||||
|
|
||||||
import static org.schabi.newpipe.util.SparseItemUtil.fetchStreamInfoAndSaveToDatabase;
|
|
||||||
import static org.schabi.newpipe.util.external_communication.ShareUtils.shareText;
|
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.view.ContextThemeWrapper;
|
import android.view.ContextThemeWrapper;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.widget.PopupMenu;
|
import android.widget.PopupMenu;
|
||||||
|
|
||||||
import androidx.fragment.app.FragmentManager;
|
import androidx.fragment.app.FragmentManager;
|
||||||
|
|
||||||
import org.schabi.newpipe.database.stream.model.StreamEntity;
|
import org.schabi.newpipe.database.stream.model.StreamEntity;
|
||||||
import org.schabi.newpipe.download.DownloadDialog;
|
import org.schabi.newpipe.download.DownloadDialog;
|
||||||
import org.schabi.newpipe.local.dialog.PlaylistDialog;
|
import org.schabi.newpipe.local.dialog.PlaylistDialog;
|
||||||
|
@ -20,6 +15,9 @@ import org.schabi.newpipe.util.SparseItemUtil;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import static org.schabi.newpipe.util.SparseItemUtil.fetchStreamInfoAndSaveToDatabase;
|
||||||
|
import static org.schabi.newpipe.util.external_communication.ShareUtils.shareText;
|
||||||
|
|
||||||
public final class QueueItemMenuUtil {
|
public final class QueueItemMenuUtil {
|
||||||
private QueueItemMenuUtil() {
|
private QueueItemMenuUtil() {
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,5 @@
|
||||||
package org.schabi.newpipe;
|
package org.schabi.newpipe;
|
||||||
|
|
||||||
import static org.schabi.newpipe.extractor.StreamingService.ServiceInfo.MediaCapability.AUDIO;
|
|
||||||
import static org.schabi.newpipe.extractor.StreamingService.ServiceInfo.MediaCapability.VIDEO;
|
|
||||||
|
|
||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
import android.app.IntentService;
|
import android.app.IntentService;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
@ -13,16 +10,11 @@ import android.content.pm.PackageManager;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.view.ContextThemeWrapper;
|
import android.view.*;
|
||||||
import android.view.LayoutInflater;
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.ViewGroup;
|
|
||||||
import android.view.WindowManager;
|
|
||||||
import android.widget.Button;
|
import android.widget.Button;
|
||||||
import android.widget.RadioButton;
|
import android.widget.RadioButton;
|
||||||
import android.widget.RadioGroup;
|
import android.widget.RadioGroup;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import androidx.annotation.DrawableRes;
|
import androidx.annotation.DrawableRes;
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
@ -40,7 +32,14 @@ import androidx.lifecycle.DefaultLifecycleObserver;
|
||||||
import androidx.lifecycle.Lifecycle;
|
import androidx.lifecycle.Lifecycle;
|
||||||
import androidx.lifecycle.LifecycleOwner;
|
import androidx.lifecycle.LifecycleOwner;
|
||||||
import androidx.preference.PreferenceManager;
|
import androidx.preference.PreferenceManager;
|
||||||
|
import icepick.Icepick;
|
||||||
|
import icepick.State;
|
||||||
|
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
|
||||||
|
import io.reactivex.rxjava3.core.Observable;
|
||||||
|
import io.reactivex.rxjava3.core.Single;
|
||||||
|
import io.reactivex.rxjava3.disposables.CompositeDisposable;
|
||||||
|
import io.reactivex.rxjava3.disposables.Disposable;
|
||||||
|
import io.reactivex.rxjava3.schedulers.Schedulers;
|
||||||
import org.schabi.newpipe.database.stream.model.StreamEntity;
|
import org.schabi.newpipe.database.stream.model.StreamEntity;
|
||||||
import org.schabi.newpipe.databinding.ListRadioIconItemBinding;
|
import org.schabi.newpipe.databinding.ListRadioIconItemBinding;
|
||||||
import org.schabi.newpipe.databinding.SingleChoiceDialogViewBinding;
|
import org.schabi.newpipe.databinding.SingleChoiceDialogViewBinding;
|
||||||
|
@ -54,16 +53,7 @@ import org.schabi.newpipe.extractor.NewPipe;
|
||||||
import org.schabi.newpipe.extractor.StreamingService;
|
import org.schabi.newpipe.extractor.StreamingService;
|
||||||
import org.schabi.newpipe.extractor.StreamingService.LinkType;
|
import org.schabi.newpipe.extractor.StreamingService.LinkType;
|
||||||
import org.schabi.newpipe.extractor.channel.ChannelInfo;
|
import org.schabi.newpipe.extractor.channel.ChannelInfo;
|
||||||
import org.schabi.newpipe.extractor.exceptions.AgeRestrictedContentException;
|
import org.schabi.newpipe.extractor.exceptions.*;
|
||||||
import org.schabi.newpipe.extractor.exceptions.ContentNotAvailableException;
|
|
||||||
import org.schabi.newpipe.extractor.exceptions.ContentNotSupportedException;
|
|
||||||
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
|
|
||||||
import org.schabi.newpipe.extractor.exceptions.GeographicRestrictionException;
|
|
||||||
import org.schabi.newpipe.extractor.exceptions.PaidContentException;
|
|
||||||
import org.schabi.newpipe.extractor.exceptions.PrivateContentException;
|
|
||||||
import org.schabi.newpipe.extractor.exceptions.ReCaptchaException;
|
|
||||||
import org.schabi.newpipe.extractor.exceptions.SoundCloudGoPlusContentException;
|
|
||||||
import org.schabi.newpipe.extractor.exceptions.YoutubeMusicPremiumContentException;
|
|
||||||
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.ktx.ExceptionUtils;
|
import org.schabi.newpipe.ktx.ExceptionUtils;
|
||||||
|
@ -75,13 +65,7 @@ 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.PlaylistPlayQueue;
|
import org.schabi.newpipe.player.playqueue.PlaylistPlayQueue;
|
||||||
import org.schabi.newpipe.player.playqueue.SinglePlayQueue;
|
import org.schabi.newpipe.player.playqueue.SinglePlayQueue;
|
||||||
import org.schabi.newpipe.util.Constants;
|
import org.schabi.newpipe.util.*;
|
||||||
import org.schabi.newpipe.util.DeviceUtils;
|
|
||||||
import org.schabi.newpipe.util.ExtractorHelper;
|
|
||||||
import org.schabi.newpipe.util.Localization;
|
|
||||||
import org.schabi.newpipe.util.NavigationHelper;
|
|
||||||
import org.schabi.newpipe.util.PermissionHelper;
|
|
||||||
import org.schabi.newpipe.util.ThemeHelper;
|
|
||||||
import org.schabi.newpipe.util.external_communication.ShareUtils;
|
import org.schabi.newpipe.util.external_communication.ShareUtils;
|
||||||
import org.schabi.newpipe.util.urlfinder.UrlFinder;
|
import org.schabi.newpipe.util.urlfinder.UrlFinder;
|
||||||
import org.schabi.newpipe.views.FocusOverlayView;
|
import org.schabi.newpipe.views.FocusOverlayView;
|
||||||
|
@ -95,14 +79,8 @@ import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
import icepick.Icepick;
|
import static org.schabi.newpipe.extractor.StreamingService.ServiceInfo.MediaCapability.AUDIO;
|
||||||
import icepick.State;
|
import static org.schabi.newpipe.extractor.StreamingService.ServiceInfo.MediaCapability.VIDEO;
|
||||||
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
|
|
||||||
import io.reactivex.rxjava3.core.Observable;
|
|
||||||
import io.reactivex.rxjava3.core.Single;
|
|
||||||
import io.reactivex.rxjava3.disposables.CompositeDisposable;
|
|
||||||
import io.reactivex.rxjava3.disposables.Disposable;
|
|
||||||
import io.reactivex.rxjava3.schedulers.Schedulers;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the url from the intent and open it in the chosen preferred player.
|
* Get the url from the intent and open it in the chosen preferred player.
|
||||||
|
@ -123,6 +101,53 @@ public class RouterActivity extends AppCompatActivity {
|
||||||
private AlertDialog alertDialogChoice = null;
|
private AlertDialog alertDialogChoice = null;
|
||||||
private FragmentManager.FragmentLifecycleCallbacks dismissListener = null;
|
private FragmentManager.FragmentLifecycleCallbacks dismissListener = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param context the context. It will be {@code finish()}ed at the end of the handling if it is
|
||||||
|
* an instance of {@link RouterActivity}.
|
||||||
|
* @param errorInfo the error information
|
||||||
|
*/
|
||||||
|
private static void handleError(final Context context, final ErrorInfo errorInfo) {
|
||||||
|
if (errorInfo.getThrowable() != null) {
|
||||||
|
errorInfo.getThrowable().printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (errorInfo.getThrowable() instanceof ReCaptchaException) {
|
||||||
|
Toast.makeText(context, R.string.recaptcha_request_toast, Toast.LENGTH_LONG).show();
|
||||||
|
// Starting ReCaptcha Challenge Activity
|
||||||
|
final Intent intent = new Intent(context, ReCaptchaActivity.class);
|
||||||
|
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||||
|
context.startActivity(intent);
|
||||||
|
} else if (errorInfo.getThrowable() != null
|
||||||
|
&& ExceptionUtils.isNetworkRelated(errorInfo.getThrowable())) {
|
||||||
|
Toast.makeText(context, R.string.network_error, Toast.LENGTH_LONG).show();
|
||||||
|
} else if (errorInfo.getThrowable() instanceof AgeRestrictedContentException) {
|
||||||
|
Toast.makeText(context, R.string.restricted_video_no_stream,
|
||||||
|
Toast.LENGTH_LONG).show();
|
||||||
|
} else if (errorInfo.getThrowable() instanceof GeographicRestrictionException) {
|
||||||
|
Toast.makeText(context, R.string.georestricted_content, Toast.LENGTH_LONG).show();
|
||||||
|
} else if (errorInfo.getThrowable() instanceof PaidContentException) {
|
||||||
|
Toast.makeText(context, R.string.paid_content, Toast.LENGTH_LONG).show();
|
||||||
|
} else if (errorInfo.getThrowable() instanceof PrivateContentException) {
|
||||||
|
Toast.makeText(context, R.string.private_content, Toast.LENGTH_LONG).show();
|
||||||
|
} else if (errorInfo.getThrowable() instanceof SoundCloudGoPlusContentException) {
|
||||||
|
Toast.makeText(context, R.string.soundcloud_go_plus_content,
|
||||||
|
Toast.LENGTH_LONG).show();
|
||||||
|
} else if (errorInfo.getThrowable() instanceof YoutubeMusicPremiumContentException) {
|
||||||
|
Toast.makeText(context, R.string.youtube_music_premium_content,
|
||||||
|
Toast.LENGTH_LONG).show();
|
||||||
|
} else if (errorInfo.getThrowable() instanceof ContentNotAvailableException) {
|
||||||
|
Toast.makeText(context, R.string.content_not_available, Toast.LENGTH_LONG).show();
|
||||||
|
} else if (errorInfo.getThrowable() instanceof ContentNotSupportedException) {
|
||||||
|
Toast.makeText(context, R.string.content_not_supported, Toast.LENGTH_LONG).show();
|
||||||
|
} else {
|
||||||
|
ErrorUtil.createNotification(context, errorInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (context instanceof RouterActivity) {
|
||||||
|
((RouterActivity) context).finish();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(final Bundle savedInstanceState) {
|
protected void onCreate(final Bundle savedInstanceState) {
|
||||||
ThemeHelper.setDayNightMode(this);
|
ThemeHelper.setDayNightMode(this);
|
||||||
|
@ -261,53 +286,6 @@ public class RouterActivity extends AppCompatActivity {
|
||||||
UserAction.SHARE_TO_NEWPIPE, "Getting service from url: " + url))));
|
UserAction.SHARE_TO_NEWPIPE, "Getting service from url: " + url))));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @param context the context. It will be {@code finish()}ed at the end of the handling if it is
|
|
||||||
* an instance of {@link RouterActivity}.
|
|
||||||
* @param errorInfo the error information
|
|
||||||
*/
|
|
||||||
private static void handleError(final Context context, final ErrorInfo errorInfo) {
|
|
||||||
if (errorInfo.getThrowable() != null) {
|
|
||||||
errorInfo.getThrowable().printStackTrace();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (errorInfo.getThrowable() instanceof ReCaptchaException) {
|
|
||||||
Toast.makeText(context, R.string.recaptcha_request_toast, Toast.LENGTH_LONG).show();
|
|
||||||
// Starting ReCaptcha Challenge Activity
|
|
||||||
final Intent intent = new Intent(context, ReCaptchaActivity.class);
|
|
||||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
|
||||||
context.startActivity(intent);
|
|
||||||
} else if (errorInfo.getThrowable() != null
|
|
||||||
&& ExceptionUtils.isNetworkRelated(errorInfo.getThrowable())) {
|
|
||||||
Toast.makeText(context, R.string.network_error, Toast.LENGTH_LONG).show();
|
|
||||||
} else if (errorInfo.getThrowable() instanceof AgeRestrictedContentException) {
|
|
||||||
Toast.makeText(context, R.string.restricted_video_no_stream,
|
|
||||||
Toast.LENGTH_LONG).show();
|
|
||||||
} else if (errorInfo.getThrowable() instanceof GeographicRestrictionException) {
|
|
||||||
Toast.makeText(context, R.string.georestricted_content, Toast.LENGTH_LONG).show();
|
|
||||||
} else if (errorInfo.getThrowable() instanceof PaidContentException) {
|
|
||||||
Toast.makeText(context, R.string.paid_content, Toast.LENGTH_LONG).show();
|
|
||||||
} else if (errorInfo.getThrowable() instanceof PrivateContentException) {
|
|
||||||
Toast.makeText(context, R.string.private_content, Toast.LENGTH_LONG).show();
|
|
||||||
} else if (errorInfo.getThrowable() instanceof SoundCloudGoPlusContentException) {
|
|
||||||
Toast.makeText(context, R.string.soundcloud_go_plus_content,
|
|
||||||
Toast.LENGTH_LONG).show();
|
|
||||||
} else if (errorInfo.getThrowable() instanceof YoutubeMusicPremiumContentException) {
|
|
||||||
Toast.makeText(context, R.string.youtube_music_premium_content,
|
|
||||||
Toast.LENGTH_LONG).show();
|
|
||||||
} else if (errorInfo.getThrowable() instanceof ContentNotAvailableException) {
|
|
||||||
Toast.makeText(context, R.string.content_not_available, Toast.LENGTH_LONG).show();
|
|
||||||
} else if (errorInfo.getThrowable() instanceof ContentNotSupportedException) {
|
|
||||||
Toast.makeText(context, R.string.content_not_supported, Toast.LENGTH_LONG).show();
|
|
||||||
} else {
|
|
||||||
ErrorUtil.createNotification(context, errorInfo);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (context instanceof RouterActivity) {
|
|
||||||
((RouterActivity) context).finish();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void showUnsupportedUrlDialog(final String url) {
|
protected void showUnsupportedUrlDialog(final String url) {
|
||||||
final Context context = getThemeWrapperContext();
|
final Context context = getThemeWrapperContext();
|
||||||
new AlertDialog.Builder(context)
|
new AlertDialog.Builder(context)
|
||||||
|
@ -396,43 +374,6 @@ public class RouterActivity extends AppCompatActivity {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* This is a helper class for checking if the choices are available and/or selected.
|
|
||||||
*/
|
|
||||||
class ChoiceAvailabilityChecker {
|
|
||||||
private final List<AdapterChoiceItem> availableChoices;
|
|
||||||
private final String selectedChoiceKey;
|
|
||||||
|
|
||||||
ChoiceAvailabilityChecker(
|
|
||||||
@NonNull final List<AdapterChoiceItem> availableChoices,
|
|
||||||
@NonNull final String selectedChoiceKey) {
|
|
||||||
this.availableChoices = availableChoices;
|
|
||||||
this.selectedChoiceKey = selectedChoiceKey;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<AdapterChoiceItem> getAvailableChoices() {
|
|
||||||
return availableChoices;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getSelectedChoiceKey() {
|
|
||||||
return selectedChoiceKey;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isAvailableAndSelected(@StringRes final int... wantedKeys) {
|
|
||||||
return Arrays.stream(wantedKeys).anyMatch(this::isAvailableAndSelected);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isAvailableAndSelected(@StringRes final int wantedKey) {
|
|
||||||
final String wanted = getString(wantedKey);
|
|
||||||
// Check if the wanted option is selected
|
|
||||||
if (!selectedChoiceKey.equals(wanted)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
// Check if it's available
|
|
||||||
return availableChoices.stream().anyMatch(item -> wanted.equals(item.key));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void showDialog(final List<AdapterChoiceItem> choices) {
|
private void showDialog(final List<AdapterChoiceItem> choices) {
|
||||||
final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
|
final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
|
||||||
|
|
||||||
|
@ -701,9 +642,61 @@ public class RouterActivity extends AppCompatActivity {
|
||||||
return playerType == null || playerType == PlayerType.MAIN;
|
return playerType == null || playerType == PlayerType.MAIN;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void openAddToPlaylistDialog() {
|
||||||
|
getPersistFragment().openAddToPlaylistDialog(currentServiceId, currentUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void openDownloadDialog() {
|
||||||
|
getPersistFragment().openDownloadDialog(currentServiceId, currentUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
private PersistentFragment getPersistFragment() {
|
||||||
|
final FragmentManager fm = getSupportFragmentManager();
|
||||||
|
PersistentFragment persistFragment =
|
||||||
|
(PersistentFragment) fm.findFragmentByTag("PERSIST_FRAGMENT");
|
||||||
|
if (persistFragment == null) {
|
||||||
|
persistFragment = new PersistentFragment();
|
||||||
|
fm.beginTransaction()
|
||||||
|
.add(persistFragment, "PERSIST_FRAGMENT")
|
||||||
|
.commitNow();
|
||||||
|
}
|
||||||
|
return persistFragment;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onRequestPermissionsResult(final int requestCode,
|
||||||
|
@NonNull final String[] permissions,
|
||||||
|
@NonNull final int[] grantResults) {
|
||||||
|
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
|
||||||
|
for (final int i : grantResults) {
|
||||||
|
if (i == PackageManager.PERMISSION_DENIED) {
|
||||||
|
finish();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (requestCode == PermissionHelper.DOWNLOAD_DIALOG_REQUEST_CODE) {
|
||||||
|
openDownloadDialog();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private String getUrl(final Intent intent) {
|
||||||
|
String foundUrl = null;
|
||||||
|
if (intent.getData() != null) {
|
||||||
|
// Called from another app
|
||||||
|
foundUrl = intent.getData().toString();
|
||||||
|
} else if (intent.getStringExtra(Intent.EXTRA_TEXT) != null) {
|
||||||
|
// Called from the share menu
|
||||||
|
final String extraText = intent.getStringExtra(Intent.EXTRA_TEXT);
|
||||||
|
foundUrl = UrlFinder.firstUrlFromInput(extraText);
|
||||||
|
}
|
||||||
|
|
||||||
|
return foundUrl;
|
||||||
|
}
|
||||||
|
|
||||||
public static class PersistentFragment extends Fragment {
|
public static class PersistentFragment extends Fragment {
|
||||||
private WeakReference<AppCompatActivity> weakContext;
|
|
||||||
private final CompositeDisposable disposables = new CompositeDisposable();
|
private final CompositeDisposable disposables = new CompositeDisposable();
|
||||||
|
private WeakReference<AppCompatActivity> weakContext;
|
||||||
private int running = 0;
|
private int running = 0;
|
||||||
|
|
||||||
private synchronized void inFlight(final boolean started) {
|
private synchronized void inFlight(final boolean started) {
|
||||||
|
@ -770,10 +763,10 @@ public class RouterActivity extends AppCompatActivity {
|
||||||
public void onResume(@NonNull final LifecycleOwner owner) {
|
public void onResume(@NonNull final LifecycleOwner owner) {
|
||||||
getLifecycle().removeObserver(this);
|
getLifecycle().removeObserver(this);
|
||||||
getActivityContext().ifPresentOrElse(context ->
|
getActivityContext().ifPresentOrElse(context ->
|
||||||
context.runOnUiThread(() -> {
|
context.runOnUiThread(() -> {
|
||||||
runnable.accept(context);
|
runnable.accept(context);
|
||||||
inFlight(false);
|
inFlight(false);
|
||||||
}),
|
}),
|
||||||
() -> inFlight(false)
|
() -> inFlight(false)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -806,7 +799,7 @@ public class RouterActivity extends AppCompatActivity {
|
||||||
Toast.LENGTH_LONG);
|
Toast.LENGTH_LONG);
|
||||||
toast.show();
|
toast.show();
|
||||||
emitter.setCancellable(toast::cancel);
|
emitter.setCancellable(toast::cancel);
|
||||||
}))));
|
}))));
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressLint("CheckResult")
|
@SuppressLint("CheckResult")
|
||||||
|
@ -817,13 +810,13 @@ public class RouterActivity extends AppCompatActivity {
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
.compose(this::pleaseWait)
|
.compose(this::pleaseWait)
|
||||||
.subscribe(result ->
|
.subscribe(result ->
|
||||||
runOnVisible(ctx -> {
|
runOnVisible(ctx -> {
|
||||||
final FragmentManager fm = ctx.getSupportFragmentManager();
|
final FragmentManager fm = ctx.getSupportFragmentManager();
|
||||||
final DownloadDialog downloadDialog = new DownloadDialog(ctx, result);
|
final DownloadDialog downloadDialog = new DownloadDialog(ctx, result);
|
||||||
// dismiss listener to be handled by FragmentManager
|
// dismiss listener to be handled by FragmentManager
|
||||||
downloadDialog.show(fm, "downloadDialog");
|
downloadDialog.show(fm, "downloadDialog");
|
||||||
}
|
}
|
||||||
), throwable -> runOnVisible(ctx ->
|
), throwable -> runOnVisible(ctx ->
|
||||||
((RouterActivity) ctx).showUnsupportedUrlDialog(currentUrl))));
|
((RouterActivity) ctx).showUnsupportedUrlDialog(currentUrl))));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -855,43 +848,6 @@ public class RouterActivity extends AppCompatActivity {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void openAddToPlaylistDialog() {
|
|
||||||
getPersistFragment().openAddToPlaylistDialog(currentServiceId, currentUrl);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void openDownloadDialog() {
|
|
||||||
getPersistFragment().openDownloadDialog(currentServiceId, currentUrl);
|
|
||||||
}
|
|
||||||
|
|
||||||
private PersistentFragment getPersistFragment() {
|
|
||||||
final FragmentManager fm = getSupportFragmentManager();
|
|
||||||
PersistentFragment persistFragment =
|
|
||||||
(PersistentFragment) fm.findFragmentByTag("PERSIST_FRAGMENT");
|
|
||||||
if (persistFragment == null) {
|
|
||||||
persistFragment = new PersistentFragment();
|
|
||||||
fm.beginTransaction()
|
|
||||||
.add(persistFragment, "PERSIST_FRAGMENT")
|
|
||||||
.commitNow();
|
|
||||||
}
|
|
||||||
return persistFragment;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onRequestPermissionsResult(final int requestCode,
|
|
||||||
@NonNull final String[] permissions,
|
|
||||||
@NonNull final int[] grantResults) {
|
|
||||||
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
|
|
||||||
for (final int i : grantResults) {
|
|
||||||
if (i == PackageManager.PERMISSION_DENIED) {
|
|
||||||
finish();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (requestCode == PermissionHelper.DOWNLOAD_DIALOG_REQUEST_CODE) {
|
|
||||||
openDownloadDialog();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class AdapterChoiceItem {
|
private static class AdapterChoiceItem {
|
||||||
final String description;
|
final String description;
|
||||||
final String key;
|
final String key;
|
||||||
|
@ -949,10 +905,9 @@ public class RouterActivity extends AppCompatActivity {
|
||||||
}
|
}
|
||||||
|
|
||||||
final Serializable serializable = intent.getSerializableExtra(KEY_CHOICE);
|
final Serializable serializable = intent.getSerializableExtra(KEY_CHOICE);
|
||||||
if (!(serializable instanceof Choice)) {
|
if (!(serializable instanceof final Choice playerChoice)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
final Choice playerChoice = (Choice) serializable;
|
|
||||||
handleChoice(playerChoice);
|
handleChoice(playerChoice);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1058,18 +1013,40 @@ public class RouterActivity extends AppCompatActivity {
|
||||||
// Utils
|
// Utils
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
@Nullable
|
/**
|
||||||
private String getUrl(final Intent intent) {
|
* This is a helper class for checking if the choices are available and/or selected.
|
||||||
String foundUrl = null;
|
*/
|
||||||
if (intent.getData() != null) {
|
class ChoiceAvailabilityChecker {
|
||||||
// Called from another app
|
private final List<AdapterChoiceItem> availableChoices;
|
||||||
foundUrl = intent.getData().toString();
|
private final String selectedChoiceKey;
|
||||||
} else if (intent.getStringExtra(Intent.EXTRA_TEXT) != null) {
|
|
||||||
// Called from the share menu
|
ChoiceAvailabilityChecker(
|
||||||
final String extraText = intent.getStringExtra(Intent.EXTRA_TEXT);
|
@NonNull final List<AdapterChoiceItem> availableChoices,
|
||||||
foundUrl = UrlFinder.firstUrlFromInput(extraText);
|
@NonNull final String selectedChoiceKey) {
|
||||||
|
this.availableChoices = availableChoices;
|
||||||
|
this.selectedChoiceKey = selectedChoiceKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
return foundUrl;
|
public List<AdapterChoiceItem> getAvailableChoices() {
|
||||||
|
return availableChoices;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSelectedChoiceKey() {
|
||||||
|
return selectedChoiceKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isAvailableAndSelected(@StringRes final int... wantedKeys) {
|
||||||
|
return Arrays.stream(wantedKeys).anyMatch(this::isAvailableAndSelected);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isAvailableAndSelected(@StringRes final int wantedKey) {
|
||||||
|
final String wanted = getString(wantedKey);
|
||||||
|
// Check if the wanted option is selected
|
||||||
|
if (!selectedChoiceKey.equals(wanted)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// Check if it's available
|
||||||
|
return availableChoices.stream().anyMatch(item -> wanted.equals(item.key));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,8 @@
|
||||||
package org.schabi.newpipe.database;
|
package org.schabi.newpipe.database;
|
||||||
|
|
||||||
import static org.schabi.newpipe.database.Migrations.DB_VER_6;
|
|
||||||
|
|
||||||
import androidx.room.Database;
|
import androidx.room.Database;
|
||||||
import androidx.room.RoomDatabase;
|
import androidx.room.RoomDatabase;
|
||||||
import androidx.room.TypeConverters;
|
import androidx.room.TypeConverters;
|
||||||
|
|
||||||
import org.schabi.newpipe.database.feed.dao.FeedDAO;
|
import org.schabi.newpipe.database.feed.dao.FeedDAO;
|
||||||
import org.schabi.newpipe.database.feed.dao.FeedGroupDAO;
|
import org.schabi.newpipe.database.feed.dao.FeedGroupDAO;
|
||||||
import org.schabi.newpipe.database.feed.model.FeedEntity;
|
import org.schabi.newpipe.database.feed.model.FeedEntity;
|
||||||
|
@ -29,6 +26,8 @@ import org.schabi.newpipe.database.stream.model.StreamStateEntity;
|
||||||
import org.schabi.newpipe.database.subscription.SubscriptionDAO;
|
import org.schabi.newpipe.database.subscription.SubscriptionDAO;
|
||||||
import org.schabi.newpipe.database.subscription.SubscriptionEntity;
|
import org.schabi.newpipe.database.subscription.SubscriptionEntity;
|
||||||
|
|
||||||
|
import static org.schabi.newpipe.database.Migrations.DB_VER_6;
|
||||||
|
|
||||||
@TypeConverters({Converters.class})
|
@TypeConverters({Converters.class})
|
||||||
@Database(
|
@Database(
|
||||||
entities = {
|
entities = {
|
||||||
|
|
|
@ -4,12 +4,11 @@ import androidx.room.Dao;
|
||||||
import androidx.room.Delete;
|
import androidx.room.Delete;
|
||||||
import androidx.room.Insert;
|
import androidx.room.Insert;
|
||||||
import androidx.room.Update;
|
import androidx.room.Update;
|
||||||
|
import io.reactivex.rxjava3.core.Flowable;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import io.reactivex.rxjava3.core.Flowable;
|
|
||||||
|
|
||||||
@Dao
|
@Dao
|
||||||
public interface BasicDAO<Entity> {
|
public interface BasicDAO<Entity> {
|
||||||
/* Inserts */
|
/* Inserts */
|
||||||
|
|
|
@ -1,11 +1,9 @@
|
||||||
package org.schabi.newpipe.database;
|
package org.schabi.newpipe.database;
|
||||||
|
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.room.migration.Migration;
|
import androidx.room.migration.Migration;
|
||||||
import androidx.sqlite.db.SupportSQLiteDatabase;
|
import androidx.sqlite.db.SupportSQLiteDatabase;
|
||||||
|
|
||||||
import org.schabi.newpipe.MainActivity;
|
import org.schabi.newpipe.MainActivity;
|
||||||
|
|
||||||
public final class Migrations {
|
public final class Migrations {
|
||||||
|
@ -24,10 +22,86 @@ public final class Migrations {
|
||||||
public static final int DB_VER_4 = 4;
|
public static final int DB_VER_4 = 4;
|
||||||
public static final int DB_VER_5 = 5;
|
public static final int DB_VER_5 = 5;
|
||||||
public static final int DB_VER_6 = 6;
|
public static final int DB_VER_6 = 6;
|
||||||
|
|
||||||
private static final String TAG = Migrations.class.getName();
|
|
||||||
public static final boolean DEBUG = MainActivity.DEBUG;
|
public static final boolean DEBUG = MainActivity.DEBUG;
|
||||||
|
public static final Migration MIGRATION_2_3 = new Migration(DB_VER_2, DB_VER_3) {
|
||||||
|
@Override
|
||||||
|
public void migrate(@NonNull final SupportSQLiteDatabase database) {
|
||||||
|
// Add NOT NULLs and new fields
|
||||||
|
database.execSQL("CREATE TABLE IF NOT EXISTS streams_new "
|
||||||
|
+ "(uid INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "
|
||||||
|
+ "service_id INTEGER NOT NULL, url TEXT NOT NULL, title TEXT NOT NULL, "
|
||||||
|
+ "stream_type TEXT NOT NULL, duration INTEGER NOT NULL, "
|
||||||
|
+ "uploader TEXT NOT NULL, thumbnail_url TEXT, view_count INTEGER, "
|
||||||
|
+ "textual_upload_date TEXT, upload_date INTEGER, "
|
||||||
|
+ "is_upload_date_approximation INTEGER)");
|
||||||
|
|
||||||
|
database.execSQL("INSERT INTO streams_new (uid, service_id, url, title, stream_type, "
|
||||||
|
+ "duration, uploader, thumbnail_url, view_count, textual_upload_date, "
|
||||||
|
+ "upload_date, is_upload_date_approximation) "
|
||||||
|
|
||||||
|
+ "SELECT uid, service_id, url, ifnull(title, ''), "
|
||||||
|
+ "ifnull(stream_type, 'VIDEO_STREAM'), ifnull(duration, 0), "
|
||||||
|
+ "ifnull(uploader, ''), ifnull(thumbnail_url, ''), NULL, NULL, NULL, NULL "
|
||||||
|
|
||||||
|
+ "FROM streams WHERE url IS NOT NULL");
|
||||||
|
|
||||||
|
database.execSQL("DROP TABLE streams");
|
||||||
|
database.execSQL("ALTER TABLE streams_new RENAME TO streams");
|
||||||
|
database.execSQL("CREATE UNIQUE INDEX index_streams_service_id_url "
|
||||||
|
+ "ON streams (service_id, url)");
|
||||||
|
|
||||||
|
// Tables for feed feature
|
||||||
|
database.execSQL("CREATE TABLE IF NOT EXISTS feed "
|
||||||
|
+ "(stream_id INTEGER NOT NULL, subscription_id INTEGER NOT NULL, "
|
||||||
|
+ "PRIMARY KEY(stream_id, subscription_id), "
|
||||||
|
+ "FOREIGN KEY(stream_id) REFERENCES streams(uid) "
|
||||||
|
+ "ON UPDATE CASCADE ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED, "
|
||||||
|
+ "FOREIGN KEY(subscription_id) REFERENCES subscriptions(uid) "
|
||||||
|
+ "ON UPDATE CASCADE ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED)");
|
||||||
|
database.execSQL("CREATE INDEX index_feed_subscription_id ON feed (subscription_id)");
|
||||||
|
database.execSQL("CREATE TABLE IF NOT EXISTS feed_group "
|
||||||
|
+ "(uid INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, name TEXT NOT NULL, "
|
||||||
|
+ "icon_id INTEGER NOT NULL, sort_order INTEGER NOT NULL)");
|
||||||
|
database.execSQL("CREATE INDEX index_feed_group_sort_order ON feed_group (sort_order)");
|
||||||
|
database.execSQL("CREATE TABLE IF NOT EXISTS feed_group_subscription_join "
|
||||||
|
+ "(group_id INTEGER NOT NULL, subscription_id INTEGER NOT NULL, "
|
||||||
|
+ "PRIMARY KEY(group_id, subscription_id), "
|
||||||
|
+ "FOREIGN KEY(group_id) REFERENCES feed_group(uid) "
|
||||||
|
+ "ON UPDATE CASCADE ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED, "
|
||||||
|
+ "FOREIGN KEY(subscription_id) REFERENCES subscriptions(uid) "
|
||||||
|
+ "ON UPDATE CASCADE ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED)");
|
||||||
|
database.execSQL("CREATE INDEX index_feed_group_subscription_join_subscription_id "
|
||||||
|
+ "ON feed_group_subscription_join (subscription_id)");
|
||||||
|
database.execSQL("CREATE TABLE IF NOT EXISTS feed_last_updated "
|
||||||
|
+ "(subscription_id INTEGER NOT NULL, last_updated INTEGER, "
|
||||||
|
+ "PRIMARY KEY(subscription_id), "
|
||||||
|
+ "FOREIGN KEY(subscription_id) REFERENCES subscriptions(uid) "
|
||||||
|
+ "ON UPDATE CASCADE ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED)");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
public static final Migration MIGRATION_3_4 = new Migration(DB_VER_3, DB_VER_4) {
|
||||||
|
@Override
|
||||||
|
public void migrate(@NonNull final SupportSQLiteDatabase database) {
|
||||||
|
database.execSQL(
|
||||||
|
"ALTER TABLE streams ADD COLUMN uploader_url TEXT"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
public static final Migration MIGRATION_4_5 = new Migration(DB_VER_4, DB_VER_5) {
|
||||||
|
@Override
|
||||||
|
public void migrate(@NonNull final SupportSQLiteDatabase database) {
|
||||||
|
database.execSQL("ALTER TABLE `subscriptions` ADD COLUMN `notification_mode` "
|
||||||
|
+ "INTEGER NOT NULL DEFAULT 0");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
public static final Migration MIGRATION_5_6 = new Migration(DB_VER_5, DB_VER_6) {
|
||||||
|
@Override
|
||||||
|
public void migrate(@NonNull final SupportSQLiteDatabase database) {
|
||||||
|
database.execSQL("ALTER TABLE `playlists` ADD COLUMN `is_thumbnail_permanent` "
|
||||||
|
+ "INTEGER NOT NULL DEFAULT 0");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
private static final String TAG = Migrations.class.getName();
|
||||||
public static final Migration MIGRATION_1_2 = new Migration(DB_VER_1, DB_VER_2) {
|
public static final Migration MIGRATION_1_2 = new Migration(DB_VER_1, DB_VER_2) {
|
||||||
@Override
|
@Override
|
||||||
public void migrate(@NonNull final SupportSQLiteDatabase database) {
|
public void migrate(@NonNull final SupportSQLiteDatabase database) {
|
||||||
|
@ -115,88 +189,6 @@ public final class Migrations {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
public static final Migration MIGRATION_2_3 = new Migration(DB_VER_2, DB_VER_3) {
|
|
||||||
@Override
|
|
||||||
public void migrate(@NonNull final SupportSQLiteDatabase database) {
|
|
||||||
// Add NOT NULLs and new fields
|
|
||||||
database.execSQL("CREATE TABLE IF NOT EXISTS streams_new "
|
|
||||||
+ "(uid INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "
|
|
||||||
+ "service_id INTEGER NOT NULL, url TEXT NOT NULL, title TEXT NOT NULL, "
|
|
||||||
+ "stream_type TEXT NOT NULL, duration INTEGER NOT NULL, "
|
|
||||||
+ "uploader TEXT NOT NULL, thumbnail_url TEXT, view_count INTEGER, "
|
|
||||||
+ "textual_upload_date TEXT, upload_date INTEGER, "
|
|
||||||
+ "is_upload_date_approximation INTEGER)");
|
|
||||||
|
|
||||||
database.execSQL("INSERT INTO streams_new (uid, service_id, url, title, stream_type, "
|
|
||||||
+ "duration, uploader, thumbnail_url, view_count, textual_upload_date, "
|
|
||||||
+ "upload_date, is_upload_date_approximation) "
|
|
||||||
|
|
||||||
+ "SELECT uid, service_id, url, ifnull(title, ''), "
|
|
||||||
+ "ifnull(stream_type, 'VIDEO_STREAM'), ifnull(duration, 0), "
|
|
||||||
+ "ifnull(uploader, ''), ifnull(thumbnail_url, ''), NULL, NULL, NULL, NULL "
|
|
||||||
|
|
||||||
+ "FROM streams WHERE url IS NOT NULL");
|
|
||||||
|
|
||||||
database.execSQL("DROP TABLE streams");
|
|
||||||
database.execSQL("ALTER TABLE streams_new RENAME TO streams");
|
|
||||||
database.execSQL("CREATE UNIQUE INDEX index_streams_service_id_url "
|
|
||||||
+ "ON streams (service_id, url)");
|
|
||||||
|
|
||||||
// Tables for feed feature
|
|
||||||
database.execSQL("CREATE TABLE IF NOT EXISTS feed "
|
|
||||||
+ "(stream_id INTEGER NOT NULL, subscription_id INTEGER NOT NULL, "
|
|
||||||
+ "PRIMARY KEY(stream_id, subscription_id), "
|
|
||||||
+ "FOREIGN KEY(stream_id) REFERENCES streams(uid) "
|
|
||||||
+ "ON UPDATE CASCADE ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED, "
|
|
||||||
+ "FOREIGN KEY(subscription_id) REFERENCES subscriptions(uid) "
|
|
||||||
+ "ON UPDATE CASCADE ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED)");
|
|
||||||
database.execSQL("CREATE INDEX index_feed_subscription_id ON feed (subscription_id)");
|
|
||||||
database.execSQL("CREATE TABLE IF NOT EXISTS feed_group "
|
|
||||||
+ "(uid INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, name TEXT NOT NULL, "
|
|
||||||
+ "icon_id INTEGER NOT NULL, sort_order INTEGER NOT NULL)");
|
|
||||||
database.execSQL("CREATE INDEX index_feed_group_sort_order ON feed_group (sort_order)");
|
|
||||||
database.execSQL("CREATE TABLE IF NOT EXISTS feed_group_subscription_join "
|
|
||||||
+ "(group_id INTEGER NOT NULL, subscription_id INTEGER NOT NULL, "
|
|
||||||
+ "PRIMARY KEY(group_id, subscription_id), "
|
|
||||||
+ "FOREIGN KEY(group_id) REFERENCES feed_group(uid) "
|
|
||||||
+ "ON UPDATE CASCADE ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED, "
|
|
||||||
+ "FOREIGN KEY(subscription_id) REFERENCES subscriptions(uid) "
|
|
||||||
+ "ON UPDATE CASCADE ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED)");
|
|
||||||
database.execSQL("CREATE INDEX index_feed_group_subscription_join_subscription_id "
|
|
||||||
+ "ON feed_group_subscription_join (subscription_id)");
|
|
||||||
database.execSQL("CREATE TABLE IF NOT EXISTS feed_last_updated "
|
|
||||||
+ "(subscription_id INTEGER NOT NULL, last_updated INTEGER, "
|
|
||||||
+ "PRIMARY KEY(subscription_id), "
|
|
||||||
+ "FOREIGN KEY(subscription_id) REFERENCES subscriptions(uid) "
|
|
||||||
+ "ON UPDATE CASCADE ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED)");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
public static final Migration MIGRATION_3_4 = new Migration(DB_VER_3, DB_VER_4) {
|
|
||||||
@Override
|
|
||||||
public void migrate(@NonNull final SupportSQLiteDatabase database) {
|
|
||||||
database.execSQL(
|
|
||||||
"ALTER TABLE streams ADD COLUMN uploader_url TEXT"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
public static final Migration MIGRATION_4_5 = new Migration(DB_VER_4, DB_VER_5) {
|
|
||||||
@Override
|
|
||||||
public void migrate(@NonNull final SupportSQLiteDatabase database) {
|
|
||||||
database.execSQL("ALTER TABLE `subscriptions` ADD COLUMN `notification_mode` "
|
|
||||||
+ "INTEGER NOT NULL DEFAULT 0");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
public static final Migration MIGRATION_5_6 = new Migration(DB_VER_5, DB_VER_6) {
|
|
||||||
@Override
|
|
||||||
public void migrate(@NonNull final SupportSQLiteDatabase database) {
|
|
||||||
database.execSQL("ALTER TABLE `playlists` ADD COLUMN `is_thumbnail_permanent` "
|
|
||||||
+ "INTEGER NOT NULL DEFAULT 0");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
private Migrations() {
|
private Migrations() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,18 +3,12 @@ package org.schabi.newpipe.database.history.dao;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.room.Dao;
|
import androidx.room.Dao;
|
||||||
import androidx.room.Query;
|
import androidx.room.Query;
|
||||||
|
import io.reactivex.rxjava3.core.Flowable;
|
||||||
import org.schabi.newpipe.database.history.model.SearchHistoryEntry;
|
import org.schabi.newpipe.database.history.model.SearchHistoryEntry;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import io.reactivex.rxjava3.core.Flowable;
|
import static org.schabi.newpipe.database.history.model.SearchHistoryEntry.*;
|
||||||
|
|
||||||
import static org.schabi.newpipe.database.history.model.SearchHistoryEntry.CREATION_DATE;
|
|
||||||
import static org.schabi.newpipe.database.history.model.SearchHistoryEntry.ID;
|
|
||||||
import static org.schabi.newpipe.database.history.model.SearchHistoryEntry.SEARCH;
|
|
||||||
import static org.schabi.newpipe.database.history.model.SearchHistoryEntry.SERVICE_ID;
|
|
||||||
import static org.schabi.newpipe.database.history.model.SearchHistoryEntry.TABLE_NAME;
|
|
||||||
|
|
||||||
@Dao
|
@Dao
|
||||||
public interface SearchHistoryDAO extends HistoryDAO<SearchHistoryEntry> {
|
public interface SearchHistoryDAO extends HistoryDAO<SearchHistoryEntry> {
|
||||||
|
|
|
@ -4,26 +4,20 @@ import androidx.annotation.Nullable;
|
||||||
import androidx.room.Dao;
|
import androidx.room.Dao;
|
||||||
import androidx.room.Query;
|
import androidx.room.Query;
|
||||||
import androidx.room.RewriteQueriesToDropUnusedColumns;
|
import androidx.room.RewriteQueriesToDropUnusedColumns;
|
||||||
|
import io.reactivex.rxjava3.core.Flowable;
|
||||||
import org.schabi.newpipe.database.history.model.StreamHistoryEntity;
|
import org.schabi.newpipe.database.history.model.StreamHistoryEntity;
|
||||||
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 java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import io.reactivex.rxjava3.core.Flowable;
|
|
||||||
|
|
||||||
import static org.schabi.newpipe.database.history.model.StreamHistoryEntity.JOIN_STREAM_ID;
|
import static org.schabi.newpipe.database.history.model.StreamHistoryEntity.JOIN_STREAM_ID;
|
||||||
import static org.schabi.newpipe.database.history.model.StreamHistoryEntity.STREAM_ACCESS_DATE;
|
import static org.schabi.newpipe.database.history.model.StreamHistoryEntity.*;
|
||||||
import static org.schabi.newpipe.database.history.model.StreamHistoryEntity.STREAM_HISTORY_TABLE;
|
|
||||||
import static org.schabi.newpipe.database.history.model.StreamHistoryEntity.STREAM_REPEAT_COUNT;
|
|
||||||
import static org.schabi.newpipe.database.stream.StreamStatisticsEntry.STREAM_LATEST_DATE;
|
import static org.schabi.newpipe.database.stream.StreamStatisticsEntry.STREAM_LATEST_DATE;
|
||||||
import static org.schabi.newpipe.database.stream.StreamStatisticsEntry.STREAM_WATCH_COUNT;
|
import static org.schabi.newpipe.database.stream.StreamStatisticsEntry.STREAM_WATCH_COUNT;
|
||||||
import static org.schabi.newpipe.database.stream.model.StreamEntity.STREAM_ID;
|
import static org.schabi.newpipe.database.stream.model.StreamEntity.STREAM_ID;
|
||||||
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.StreamStateEntity.JOIN_STREAM_ID_ALIAS;
|
import static org.schabi.newpipe.database.stream.model.StreamStateEntity.*;
|
||||||
import static org.schabi.newpipe.database.stream.model.StreamStateEntity.STREAM_PROGRESS_MILLIS;
|
|
||||||
import static org.schabi.newpipe.database.stream.model.StreamStateEntity.STREAM_STATE_TABLE;
|
|
||||||
|
|
||||||
@Dao
|
@Dao
|
||||||
public abstract class StreamHistoryDAO implements HistoryDAO<StreamHistoryEntity> {
|
public abstract class StreamHistoryDAO implements HistoryDAO<StreamHistoryEntity> {
|
||||||
|
|
|
@ -5,15 +5,12 @@ import androidx.room.ColumnInfo;
|
||||||
import androidx.room.Entity;
|
import androidx.room.Entity;
|
||||||
import androidx.room.ForeignKey;
|
import androidx.room.ForeignKey;
|
||||||
import androidx.room.Index;
|
import androidx.room.Index;
|
||||||
|
|
||||||
import org.schabi.newpipe.database.stream.model.StreamEntity;
|
import org.schabi.newpipe.database.stream.model.StreamEntity;
|
||||||
|
|
||||||
import java.time.OffsetDateTime;
|
import java.time.OffsetDateTime;
|
||||||
|
|
||||||
import static androidx.room.ForeignKey.CASCADE;
|
import static androidx.room.ForeignKey.CASCADE;
|
||||||
import static org.schabi.newpipe.database.history.model.StreamHistoryEntity.JOIN_STREAM_ID;
|
import static org.schabi.newpipe.database.history.model.StreamHistoryEntity.*;
|
||||||
import static org.schabi.newpipe.database.history.model.StreamHistoryEntity.STREAM_ACCESS_DATE;
|
|
||||||
import static org.schabi.newpipe.database.history.model.StreamHistoryEntity.STREAM_HISTORY_TABLE;
|
|
||||||
|
|
||||||
@Entity(tableName = STREAM_HISTORY_TABLE,
|
@Entity(tableName = STREAM_HISTORY_TABLE,
|
||||||
primaryKeys = {JOIN_STREAM_ID, STREAM_ACCESS_DATE},
|
primaryKeys = {JOIN_STREAM_ID, STREAM_ACCESS_DATE},
|
||||||
|
@ -42,8 +39,8 @@ public class StreamHistoryEntity {
|
||||||
private long repeatCount;
|
private long repeatCount;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param streamUid the stream id this history item will refer to
|
* @param streamUid the stream id this history item will refer to
|
||||||
* @param accessDate the last time the stream was accessed
|
* @param accessDate the last time the stream was accessed
|
||||||
* @param repeatCount the total number of views this stream received
|
* @param repeatCount the total number of views this stream received
|
||||||
*/
|
*/
|
||||||
public StreamHistoryEntity(final long streamUid,
|
public StreamHistoryEntity(final long streamUid,
|
||||||
|
|
|
@ -9,8 +9,6 @@ import java.util.stream.Collectors;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
public interface PlaylistLocalItem extends LocalItem {
|
public interface PlaylistLocalItem extends LocalItem {
|
||||||
String getOrderingName();
|
|
||||||
|
|
||||||
static List<PlaylistLocalItem> merge(
|
static List<PlaylistLocalItem> merge(
|
||||||
final List<PlaylistMetadataEntry> localPlaylists,
|
final List<PlaylistMetadataEntry> localPlaylists,
|
||||||
final List<PlaylistRemoteEntity> remotePlaylists) {
|
final List<PlaylistRemoteEntity> remotePlaylists) {
|
||||||
|
@ -19,4 +17,6 @@ public interface PlaylistLocalItem extends LocalItem {
|
||||||
Comparator.nullsLast(String.CASE_INSENSITIVE_ORDER)))
|
Comparator.nullsLast(String.CASE_INSENSITIVE_ORDER)))
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String getOrderingName();
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,9 +2,7 @@ package org.schabi.newpipe.database.playlist;
|
||||||
|
|
||||||
import androidx.room.ColumnInfo;
|
import androidx.room.ColumnInfo;
|
||||||
|
|
||||||
import static org.schabi.newpipe.database.playlist.model.PlaylistEntity.PLAYLIST_ID;
|
import static org.schabi.newpipe.database.playlist.model.PlaylistEntity.*;
|
||||||
import static org.schabi.newpipe.database.playlist.model.PlaylistEntity.PLAYLIST_NAME;
|
|
||||||
import static org.schabi.newpipe.database.playlist.model.PlaylistEntity.PLAYLIST_THUMBNAIL_URL;
|
|
||||||
|
|
||||||
public class PlaylistMetadataEntry implements PlaylistLocalItem {
|
public class PlaylistMetadataEntry implements PlaylistLocalItem {
|
||||||
public static final String PLAYLIST_STREAM_COUNT = "streamCount";
|
public static final String PLAYLIST_STREAM_COUNT = "streamCount";
|
||||||
|
|
|
@ -2,14 +2,12 @@ package org.schabi.newpipe.database.playlist.dao;
|
||||||
|
|
||||||
import androidx.room.Dao;
|
import androidx.room.Dao;
|
||||||
import androidx.room.Query;
|
import androidx.room.Query;
|
||||||
|
import io.reactivex.rxjava3.core.Flowable;
|
||||||
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;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import io.reactivex.rxjava3.core.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_TABLE;
|
import static org.schabi.newpipe.database.playlist.model.PlaylistEntity.PLAYLIST_TABLE;
|
||||||
|
|
||||||
|
|
|
@ -3,18 +3,13 @@ package org.schabi.newpipe.database.playlist.dao;
|
||||||
import androidx.room.Dao;
|
import androidx.room.Dao;
|
||||||
import androidx.room.Query;
|
import androidx.room.Query;
|
||||||
import androidx.room.Transaction;
|
import androidx.room.Transaction;
|
||||||
|
import io.reactivex.rxjava3.core.Flowable;
|
||||||
import org.schabi.newpipe.database.BasicDAO;
|
import org.schabi.newpipe.database.BasicDAO;
|
||||||
import org.schabi.newpipe.database.playlist.model.PlaylistRemoteEntity;
|
import org.schabi.newpipe.database.playlist.model.PlaylistRemoteEntity;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import io.reactivex.rxjava3.core.Flowable;
|
import static org.schabi.newpipe.database.playlist.model.PlaylistRemoteEntity.*;
|
||||||
|
|
||||||
import static org.schabi.newpipe.database.playlist.model.PlaylistRemoteEntity.REMOTE_PLAYLIST_ID;
|
|
||||||
import static org.schabi.newpipe.database.playlist.model.PlaylistRemoteEntity.REMOTE_PLAYLIST_SERVICE_ID;
|
|
||||||
import static org.schabi.newpipe.database.playlist.model.PlaylistRemoteEntity.REMOTE_PLAYLIST_TABLE;
|
|
||||||
import static org.schabi.newpipe.database.playlist.model.PlaylistRemoteEntity.REMOTE_PLAYLIST_URL;
|
|
||||||
|
|
||||||
@Dao
|
@Dao
|
||||||
public interface PlaylistRemoteDAO extends BasicDAO<PlaylistRemoteEntity> {
|
public interface PlaylistRemoteDAO extends BasicDAO<PlaylistRemoteEntity> {
|
||||||
|
|
|
@ -4,7 +4,7 @@ import androidx.room.Dao;
|
||||||
import androidx.room.Query;
|
import androidx.room.Query;
|
||||||
import androidx.room.RewriteQueriesToDropUnusedColumns;
|
import androidx.room.RewriteQueriesToDropUnusedColumns;
|
||||||
import androidx.room.Transaction;
|
import androidx.room.Transaction;
|
||||||
|
import io.reactivex.rxjava3.core.Flowable;
|
||||||
import org.schabi.newpipe.database.BasicDAO;
|
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;
|
||||||
|
@ -12,23 +12,12 @@ import org.schabi.newpipe.database.playlist.model.PlaylistStreamEntity;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import io.reactivex.rxjava3.core.Flowable;
|
|
||||||
|
|
||||||
import static org.schabi.newpipe.database.playlist.PlaylistMetadataEntry.PLAYLIST_STREAM_COUNT;
|
import static org.schabi.newpipe.database.playlist.PlaylistMetadataEntry.PLAYLIST_STREAM_COUNT;
|
||||||
import static org.schabi.newpipe.database.playlist.model.PlaylistEntity.PLAYLIST_ID;
|
import static org.schabi.newpipe.database.playlist.model.PlaylistEntity.*;
|
||||||
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_THUMBNAIL_URL;
|
|
||||||
import static org.schabi.newpipe.database.playlist.model.PlaylistStreamEntity.JOIN_INDEX;
|
|
||||||
import static org.schabi.newpipe.database.playlist.model.PlaylistStreamEntity.JOIN_PLAYLIST_ID;
|
|
||||||
import static org.schabi.newpipe.database.playlist.model.PlaylistStreamEntity.JOIN_STREAM_ID;
|
import static org.schabi.newpipe.database.playlist.model.PlaylistStreamEntity.JOIN_STREAM_ID;
|
||||||
import static org.schabi.newpipe.database.playlist.model.PlaylistStreamEntity.PLAYLIST_STREAM_JOIN_TABLE;
|
import static org.schabi.newpipe.database.playlist.model.PlaylistStreamEntity.*;
|
||||||
import static org.schabi.newpipe.database.stream.model.StreamEntity.STREAM_ID;
|
import static org.schabi.newpipe.database.stream.model.StreamEntity.*;
|
||||||
import static org.schabi.newpipe.database.stream.model.StreamEntity.STREAM_TABLE;
|
import static org.schabi.newpipe.database.stream.model.StreamStateEntity.*;
|
||||||
import static org.schabi.newpipe.database.stream.model.StreamEntity.STREAM_THUMBNAIL_URL;
|
|
||||||
import static org.schabi.newpipe.database.stream.model.StreamStateEntity.JOIN_STREAM_ID_ALIAS;
|
|
||||||
import static org.schabi.newpipe.database.stream.model.StreamStateEntity.STREAM_PROGRESS_MILLIS;
|
|
||||||
import static org.schabi.newpipe.database.stream.model.StreamStateEntity.STREAM_STATE_TABLE;
|
|
||||||
|
|
||||||
@Dao
|
@Dao
|
||||||
public interface PlaylistStreamDAO extends BasicDAO<PlaylistStreamEntity> {
|
public interface PlaylistStreamDAO extends BasicDAO<PlaylistStreamEntity> {
|
||||||
|
|
|
@ -1,22 +1,13 @@
|
||||||
package org.schabi.newpipe.database.playlist.model;
|
package org.schabi.newpipe.database.playlist.model;
|
||||||
|
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
|
import androidx.room.*;
|
||||||
import androidx.room.ColumnInfo;
|
|
||||||
import androidx.room.Entity;
|
|
||||||
import androidx.room.Ignore;
|
|
||||||
import androidx.room.Index;
|
|
||||||
import androidx.room.PrimaryKey;
|
|
||||||
|
|
||||||
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;
|
||||||
|
|
||||||
import static org.schabi.newpipe.database.LocalItem.LocalItemType.PLAYLIST_REMOTE_ITEM;
|
import static org.schabi.newpipe.database.LocalItem.LocalItemType.PLAYLIST_REMOTE_ITEM;
|
||||||
import static org.schabi.newpipe.database.playlist.model.PlaylistRemoteEntity.REMOTE_PLAYLIST_NAME;
|
import static org.schabi.newpipe.database.playlist.model.PlaylistRemoteEntity.*;
|
||||||
import static org.schabi.newpipe.database.playlist.model.PlaylistRemoteEntity.REMOTE_PLAYLIST_SERVICE_ID;
|
|
||||||
import static org.schabi.newpipe.database.playlist.model.PlaylistRemoteEntity.REMOTE_PLAYLIST_TABLE;
|
|
||||||
import static org.schabi.newpipe.database.playlist.model.PlaylistRemoteEntity.REMOTE_PLAYLIST_URL;
|
|
||||||
|
|
||||||
@Entity(tableName = REMOTE_PLAYLIST_TABLE,
|
@Entity(tableName = REMOTE_PLAYLIST_TABLE,
|
||||||
indices = {
|
indices = {
|
||||||
|
|
|
@ -4,14 +4,10 @@ import androidx.room.ColumnInfo;
|
||||||
import androidx.room.Entity;
|
import androidx.room.Entity;
|
||||||
import androidx.room.ForeignKey;
|
import androidx.room.ForeignKey;
|
||||||
import androidx.room.Index;
|
import androidx.room.Index;
|
||||||
|
|
||||||
import org.schabi.newpipe.database.stream.model.StreamEntity;
|
import org.schabi.newpipe.database.stream.model.StreamEntity;
|
||||||
|
|
||||||
import static androidx.room.ForeignKey.CASCADE;
|
import static androidx.room.ForeignKey.CASCADE;
|
||||||
import static org.schabi.newpipe.database.playlist.model.PlaylistStreamEntity.JOIN_INDEX;
|
import static org.schabi.newpipe.database.playlist.model.PlaylistStreamEntity.*;
|
||||||
import static org.schabi.newpipe.database.playlist.model.PlaylistStreamEntity.JOIN_PLAYLIST_ID;
|
|
||||||
import static org.schabi.newpipe.database.playlist.model.PlaylistStreamEntity.JOIN_STREAM_ID;
|
|
||||||
import static org.schabi.newpipe.database.playlist.model.PlaylistStreamEntity.PLAYLIST_STREAM_JOIN_TABLE;
|
|
||||||
|
|
||||||
@Entity(tableName = PLAYLIST_STREAM_JOIN_TABLE,
|
@Entity(tableName = PLAYLIST_STREAM_JOIN_TABLE,
|
||||||
primaryKeys = {JOIN_PLAYLIST_ID, JOIN_INDEX},
|
primaryKeys = {JOIN_PLAYLIST_ID, JOIN_INDEX},
|
||||||
|
|
|
@ -1,18 +1,12 @@
|
||||||
package org.schabi.newpipe.database.stream.dao;
|
package org.schabi.newpipe.database.stream.dao;
|
||||||
|
|
||||||
import androidx.room.Dao;
|
import androidx.room.*;
|
||||||
import androidx.room.Insert;
|
import io.reactivex.rxjava3.core.Flowable;
|
||||||
import androidx.room.OnConflictStrategy;
|
|
||||||
import androidx.room.Query;
|
|
||||||
import androidx.room.Transaction;
|
|
||||||
|
|
||||||
import org.schabi.newpipe.database.BasicDAO;
|
import org.schabi.newpipe.database.BasicDAO;
|
||||||
import org.schabi.newpipe.database.stream.model.StreamStateEntity;
|
import org.schabi.newpipe.database.stream.model.StreamStateEntity;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import io.reactivex.rxjava3.core.Flowable;
|
|
||||||
|
|
||||||
import static org.schabi.newpipe.database.stream.model.StreamStateEntity.JOIN_STREAM_ID;
|
import static org.schabi.newpipe.database.stream.model.StreamStateEntity.JOIN_STREAM_ID;
|
||||||
import static org.schabi.newpipe.database.stream.model.StreamStateEntity.STREAM_STATE_TABLE;
|
import static org.schabi.newpipe.database.stream.model.StreamStateEntity.STREAM_STATE_TABLE;
|
||||||
|
|
||||||
|
|
|
@ -26,21 +26,19 @@ public class StreamStateEntity {
|
||||||
// for some other joins already
|
// for some other joins already
|
||||||
public static final String JOIN_STREAM_ID_ALIAS = "stream_id_alias";
|
public static final String JOIN_STREAM_ID_ALIAS = "stream_id_alias";
|
||||||
public static final String STREAM_PROGRESS_MILLIS = "progress_time";
|
public static final String STREAM_PROGRESS_MILLIS = "progress_time";
|
||||||
|
|
||||||
/**
|
|
||||||
* Playback state will not be saved, if playback time is less than this threshold (5000ms = 5s).
|
|
||||||
*/
|
|
||||||
private static final long PLAYBACK_SAVE_THRESHOLD_START_MILLISECONDS = 5000;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stream will be considered finished if the playback time left exceeds this threshold
|
* Stream will be considered finished if the playback time left exceeds this threshold
|
||||||
* (60000ms = 60s).
|
* (60000ms = 60s).
|
||||||
|
*
|
||||||
* @see #isFinished(long)
|
* @see #isFinished(long)
|
||||||
* @see org.schabi.newpipe.database.feed.dao.FeedDAO#getLiveOrNotPlayedStreams()
|
* @see org.schabi.newpipe.database.feed.dao.FeedDAO#getLiveOrNotPlayedStreams()
|
||||||
* @see org.schabi.newpipe.database.feed.dao.FeedDAO#getLiveOrNotPlayedStreamsForGroup(long)
|
* @see org.schabi.newpipe.database.feed.dao.FeedDAO#getLiveOrNotPlayedStreamsForGroup(long)
|
||||||
*/
|
*/
|
||||||
public static final long PLAYBACK_FINISHED_END_MILLISECONDS = 60000;
|
public static final long PLAYBACK_FINISHED_END_MILLISECONDS = 60000;
|
||||||
|
/**
|
||||||
|
* Playback state will not be saved, if playback time is less than this threshold (5000ms = 5s).
|
||||||
|
*/
|
||||||
|
private static final long PLAYBACK_SAVE_THRESHOLD_START_MILLISECONDS = 5000;
|
||||||
@ColumnInfo(name = JOIN_STREAM_ID)
|
@ColumnInfo(name = JOIN_STREAM_ID)
|
||||||
private long streamUid;
|
private long streamUid;
|
||||||
|
|
||||||
|
@ -71,6 +69,7 @@ public class StreamStateEntity {
|
||||||
/**
|
/**
|
||||||
* The state will be considered valid, and thus be saved, if the progress is more than {@link
|
* The state will be considered valid, and thus be saved, if the progress is more than {@link
|
||||||
* #PLAYBACK_SAVE_THRESHOLD_START_MILLISECONDS} or at least 1/4 of the video length.
|
* #PLAYBACK_SAVE_THRESHOLD_START_MILLISECONDS} or at least 1/4 of the video length.
|
||||||
|
*
|
||||||
* @param durationInSeconds the duration of the stream connected with this state, in seconds
|
* @param durationInSeconds the duration of the stream connected with this state, in seconds
|
||||||
* @return whether this stream state entity should be saved or not
|
* @return whether this stream state entity should be saved or not
|
||||||
*/
|
*/
|
||||||
|
@ -85,10 +84,11 @@ public class StreamStateEntity {
|
||||||
* The state will be saved anyway, so that it can be shown under stream info items, but the
|
* The state will be saved anyway, so that it can be shown under stream info items, but the
|
||||||
* player will not resume if a state is considered as finished. Finished streams are also the
|
* player will not resume if a state is considered as finished. Finished streams are also the
|
||||||
* ones that can be filtered out in the feed fragment.
|
* ones that can be filtered out in the feed fragment.
|
||||||
* @see org.schabi.newpipe.database.feed.dao.FeedDAO#getLiveOrNotPlayedStreams()
|
*
|
||||||
* @see org.schabi.newpipe.database.feed.dao.FeedDAO#getLiveOrNotPlayedStreamsForGroup(long)
|
|
||||||
* @param durationInSeconds the duration of the stream connected with this state, in seconds
|
* @param durationInSeconds the duration of the stream connected with this state, in seconds
|
||||||
* @return whether the stream is finished or not
|
* @return whether the stream is finished or not
|
||||||
|
* @see org.schabi.newpipe.database.feed.dao.FeedDAO#getLiveOrNotPlayedStreams()
|
||||||
|
* @see org.schabi.newpipe.database.feed.dao.FeedDAO#getLiveOrNotPlayedStreamsForGroup(long)
|
||||||
*/
|
*/
|
||||||
public boolean isFinished(final long durationInSeconds) {
|
public boolean isFinished(final long durationInSeconds) {
|
||||||
return progressMillis >= durationInSeconds * 1000 - PLAYBACK_FINISHED_END_MILLISECONDS
|
return progressMillis >= durationInSeconds * 1000 - PLAYBACK_FINISHED_END_MILLISECONDS
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package org.schabi.newpipe.database.subscription;
|
package org.schabi.newpipe.database.subscription;
|
||||||
|
|
||||||
import androidx.annotation.IntDef;
|
import androidx.annotation.IntDef;
|
||||||
|
|
||||||
import java.lang.annotation.Retention;
|
import java.lang.annotation.Retention;
|
||||||
import java.lang.annotation.RetentionPolicy;
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
|
||||||
|
|
|
@ -1,19 +1,12 @@
|
||||||
package org.schabi.newpipe.database.subscription;
|
package org.schabi.newpipe.database.subscription;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.room.ColumnInfo;
|
import androidx.room.*;
|
||||||
import androidx.room.Entity;
|
|
||||||
import androidx.room.Ignore;
|
|
||||||
import androidx.room.Index;
|
|
||||||
import androidx.room.PrimaryKey;
|
|
||||||
|
|
||||||
import org.schabi.newpipe.extractor.channel.ChannelInfo;
|
import org.schabi.newpipe.extractor.channel.ChannelInfo;
|
||||||
import org.schabi.newpipe.extractor.channel.ChannelInfoItem;
|
import org.schabi.newpipe.extractor.channel.ChannelInfoItem;
|
||||||
import org.schabi.newpipe.util.Constants;
|
import org.schabi.newpipe.util.Constants;
|
||||||
|
|
||||||
import static org.schabi.newpipe.database.subscription.SubscriptionEntity.SUBSCRIPTION_SERVICE_ID;
|
import static org.schabi.newpipe.database.subscription.SubscriptionEntity.*;
|
||||||
import static org.schabi.newpipe.database.subscription.SubscriptionEntity.SUBSCRIPTION_TABLE;
|
|
||||||
import static org.schabi.newpipe.database.subscription.SubscriptionEntity.SUBSCRIPTION_URL;
|
|
||||||
|
|
||||||
@Entity(tableName = SUBSCRIPTION_TABLE,
|
@Entity(tableName = SUBSCRIPTION_TABLE,
|
||||||
indices = {@Index(value = {SUBSCRIPTION_SERVICE_ID, SUBSCRIPTION_URL}, unique = true)})
|
indices = {@Index(value = {SUBSCRIPTION_SERVICE_ID, SUBSCRIPTION_URL}, unique = true)})
|
||||||
|
@ -26,7 +19,7 @@ public class SubscriptionEntity {
|
||||||
public static final String SUBSCRIPTION_AVATAR_URL = "avatar_url";
|
public static final String SUBSCRIPTION_AVATAR_URL = "avatar_url";
|
||||||
public static final String SUBSCRIPTION_SUBSCRIBER_COUNT = "subscriber_count";
|
public static final String SUBSCRIPTION_SUBSCRIBER_COUNT = "subscriber_count";
|
||||||
public static final String SUBSCRIPTION_DESCRIPTION = "description";
|
public static final String SUBSCRIPTION_DESCRIPTION = "description";
|
||||||
public static final String SUBSCRIPTION_NOTIFICATION_MODE = "notification_mode";
|
public static final String SUBSCRIPTION_NOTIFICATION_MODE = "notification_mode";
|
||||||
|
|
||||||
@PrimaryKey(autoGenerate = true)
|
@PrimaryKey(autoGenerate = true)
|
||||||
private long uid = 0;
|
private long uid = 0;
|
||||||
|
@ -167,20 +160,16 @@ public class SubscriptionEntity {
|
||||||
if (!url.equals(that.url)) {
|
if (!url.equals(that.url)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (name != null ? !name.equals(that.name) : that.name != null) {
|
if (!java.util.Objects.equals(name, that.name)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (avatarUrl != null ? !avatarUrl.equals(that.avatarUrl) : that.avatarUrl != null) {
|
if (!java.util.Objects.equals(avatarUrl, that.avatarUrl)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (subscriberCount != null
|
if (!java.util.Objects.equals(subscriberCount, that.subscriberCount)) {
|
||||||
? !subscriberCount.equals(that.subscriberCount)
|
|
||||||
: that.subscriberCount != null) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return description != null
|
return java.util.Objects.equals(description, that.description);
|
||||||
? description.equals(that.description)
|
|
||||||
: that.description == null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -6,17 +6,14 @@ import android.view.Menu;
|
||||||
import android.view.MenuInflater;
|
import android.view.MenuInflater;
|
||||||
import android.view.MenuItem;
|
import android.view.MenuItem;
|
||||||
import android.view.ViewTreeObserver;
|
import android.view.ViewTreeObserver;
|
||||||
|
|
||||||
import androidx.appcompat.app.ActionBar;
|
import androidx.appcompat.app.ActionBar;
|
||||||
import androidx.appcompat.app.AppCompatActivity;
|
import androidx.appcompat.app.AppCompatActivity;
|
||||||
import androidx.fragment.app.FragmentTransaction;
|
import androidx.fragment.app.FragmentTransaction;
|
||||||
|
|
||||||
import org.schabi.newpipe.R;
|
import org.schabi.newpipe.R;
|
||||||
import org.schabi.newpipe.databinding.ActivityDownloaderBinding;
|
import org.schabi.newpipe.databinding.ActivityDownloaderBinding;
|
||||||
import org.schabi.newpipe.util.DeviceUtils;
|
import org.schabi.newpipe.util.DeviceUtils;
|
||||||
import org.schabi.newpipe.util.ThemeHelper;
|
import org.schabi.newpipe.util.ThemeHelper;
|
||||||
import org.schabi.newpipe.views.FocusOverlayView;
|
import org.schabi.newpipe.views.FocusOverlayView;
|
||||||
|
|
||||||
import us.shandian.giga.service.DownloadManagerService;
|
import us.shandian.giga.service.DownloadManagerService;
|
||||||
import us.shandian.giga.ui.fragment.MissionsFragment;
|
import us.shandian.giga.ui.fragment.MissionsFragment;
|
||||||
|
|
||||||
|
@ -53,12 +50,12 @@ public class DownloadActivity extends AppCompatActivity {
|
||||||
|
|
||||||
getWindow().getDecorView().getViewTreeObserver()
|
getWindow().getDecorView().getViewTreeObserver()
|
||||||
.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
|
.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onGlobalLayout() {
|
public void onGlobalLayout() {
|
||||||
updateFragments();
|
updateFragments();
|
||||||
getWindow().getDecorView().getViewTreeObserver().removeOnGlobalLayoutListener(this);
|
getWindow().getDecorView().getViewTreeObserver().removeOnGlobalLayoutListener(this);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (DeviceUtils.isTv(this)) {
|
if (DeviceUtils.isTv(this)) {
|
||||||
FocusOverlayView.setupFocusObserver(this);
|
FocusOverlayView.setupFocusObserver(this);
|
||||||
|
|
|
@ -1,17 +1,8 @@
|
||||||
package org.schabi.newpipe.download;
|
package org.schabi.newpipe.download;
|
||||||
|
|
||||||
import static org.schabi.newpipe.extractor.stream.DeliveryMethod.PROGRESSIVE_HTTP;
|
|
||||||
import static org.schabi.newpipe.util.ListHelper.getStreamsOfSpecifiedDelivery;
|
|
||||||
import static org.schabi.newpipe.util.Localization.assureCorrectAppLanguage;
|
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.content.ComponentName;
|
import android.content.*;
|
||||||
import android.content.Context;
|
|
||||||
import android.content.DialogInterface;
|
|
||||||
import android.content.DialogInterface.OnDismissListener;
|
import android.content.DialogInterface.OnDismissListener;
|
||||||
import android.content.Intent;
|
|
||||||
import android.content.ServiceConnection;
|
|
||||||
import android.content.SharedPreferences;
|
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Environment;
|
import android.os.Environment;
|
||||||
|
@ -24,7 +15,6 @@ import android.widget.AdapterView;
|
||||||
import android.widget.RadioGroup;
|
import android.widget.RadioGroup;
|
||||||
import android.widget.SeekBar;
|
import android.widget.SeekBar;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import androidx.activity.result.ActivityResult;
|
import androidx.activity.result.ActivityResult;
|
||||||
import androidx.activity.result.ActivityResultLauncher;
|
import androidx.activity.result.ActivityResultLauncher;
|
||||||
import androidx.activity.result.contract.ActivityResultContracts.StartActivityForResult;
|
import androidx.activity.result.contract.ActivityResultContracts.StartActivityForResult;
|
||||||
|
@ -39,9 +29,10 @@ import androidx.collection.SparseArrayCompat;
|
||||||
import androidx.documentfile.provider.DocumentFile;
|
import androidx.documentfile.provider.DocumentFile;
|
||||||
import androidx.fragment.app.DialogFragment;
|
import androidx.fragment.app.DialogFragment;
|
||||||
import androidx.preference.PreferenceManager;
|
import androidx.preference.PreferenceManager;
|
||||||
|
|
||||||
import com.nononsenseapps.filepicker.Utils;
|
import com.nononsenseapps.filepicker.Utils;
|
||||||
|
import icepick.Icepick;
|
||||||
|
import icepick.State;
|
||||||
|
import io.reactivex.rxjava3.disposables.CompositeDisposable;
|
||||||
import org.schabi.newpipe.MainActivity;
|
import org.schabi.newpipe.MainActivity;
|
||||||
import org.schabi.newpipe.R;
|
import org.schabi.newpipe.R;
|
||||||
import org.schabi.newpipe.databinding.DownloadDialogBinding;
|
import org.schabi.newpipe.databinding.DownloadDialogBinding;
|
||||||
|
@ -51,24 +42,19 @@ import org.schabi.newpipe.error.UserAction;
|
||||||
import org.schabi.newpipe.extractor.MediaFormat;
|
import org.schabi.newpipe.extractor.MediaFormat;
|
||||||
import org.schabi.newpipe.extractor.NewPipe;
|
import org.schabi.newpipe.extractor.NewPipe;
|
||||||
import org.schabi.newpipe.extractor.localization.Localization;
|
import org.schabi.newpipe.extractor.localization.Localization;
|
||||||
import org.schabi.newpipe.extractor.stream.AudioStream;
|
import org.schabi.newpipe.extractor.stream.*;
|
||||||
import org.schabi.newpipe.extractor.stream.Stream;
|
|
||||||
import org.schabi.newpipe.extractor.stream.StreamInfo;
|
|
||||||
import org.schabi.newpipe.extractor.stream.SubtitlesStream;
|
|
||||||
import org.schabi.newpipe.extractor.stream.VideoStream;
|
|
||||||
import org.schabi.newpipe.settings.NewPipeSettings;
|
import org.schabi.newpipe.settings.NewPipeSettings;
|
||||||
import org.schabi.newpipe.streams.io.NoFileManagerSafeGuard;
|
import org.schabi.newpipe.streams.io.NoFileManagerSafeGuard;
|
||||||
import org.schabi.newpipe.streams.io.StoredDirectoryHelper;
|
import org.schabi.newpipe.streams.io.StoredDirectoryHelper;
|
||||||
import org.schabi.newpipe.streams.io.StoredFileHelper;
|
import org.schabi.newpipe.streams.io.StoredFileHelper;
|
||||||
import org.schabi.newpipe.util.FilePickerActivityHelper;
|
import org.schabi.newpipe.util.*;
|
||||||
import org.schabi.newpipe.util.FilenameUtils;
|
|
||||||
import org.schabi.newpipe.util.ListHelper;
|
|
||||||
import org.schabi.newpipe.util.PermissionHelper;
|
|
||||||
import org.schabi.newpipe.util.SecondaryStreamHelper;
|
|
||||||
import org.schabi.newpipe.util.SimpleOnSeekBarChangeListener;
|
|
||||||
import org.schabi.newpipe.util.StreamItemAdapter;
|
|
||||||
import org.schabi.newpipe.util.StreamItemAdapter.StreamSizeWrapper;
|
import org.schabi.newpipe.util.StreamItemAdapter.StreamSizeWrapper;
|
||||||
import org.schabi.newpipe.util.ThemeHelper;
|
import us.shandian.giga.get.MissionRecoveryInfo;
|
||||||
|
import us.shandian.giga.postprocessing.Postprocessing;
|
||||||
|
import us.shandian.giga.service.DownloadManager;
|
||||||
|
import us.shandian.giga.service.DownloadManagerService;
|
||||||
|
import us.shandian.giga.service.DownloadManagerService.DownloadManagerBinder;
|
||||||
|
import us.shandian.giga.service.MissionState;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
@ -77,21 +63,15 @@ import java.util.Locale;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
import icepick.Icepick;
|
import static org.schabi.newpipe.extractor.stream.DeliveryMethod.PROGRESSIVE_HTTP;
|
||||||
import icepick.State;
|
import static org.schabi.newpipe.util.ListHelper.getStreamsOfSpecifiedDelivery;
|
||||||
import io.reactivex.rxjava3.disposables.CompositeDisposable;
|
import static org.schabi.newpipe.util.Localization.assureCorrectAppLanguage;
|
||||||
import us.shandian.giga.get.MissionRecoveryInfo;
|
|
||||||
import us.shandian.giga.postprocessing.Postprocessing;
|
|
||||||
import us.shandian.giga.service.DownloadManager;
|
|
||||||
import us.shandian.giga.service.DownloadManagerService;
|
|
||||||
import us.shandian.giga.service.DownloadManagerService.DownloadManagerBinder;
|
|
||||||
import us.shandian.giga.service.MissionState;
|
|
||||||
|
|
||||||
public class DownloadDialog extends DialogFragment
|
public class DownloadDialog extends DialogFragment
|
||||||
implements RadioGroup.OnCheckedChangeListener, AdapterView.OnItemSelectedListener {
|
implements RadioGroup.OnCheckedChangeListener, AdapterView.OnItemSelectedListener {
|
||||||
private static final String TAG = "DialogFragment";
|
private static final String TAG = "DialogFragment";
|
||||||
private static final boolean DEBUG = MainActivity.DEBUG;
|
private static final boolean DEBUG = MainActivity.DEBUG;
|
||||||
|
private final CompositeDisposable disposables = new CompositeDisposable();
|
||||||
@State
|
@State
|
||||||
StreamInfo currentInfo;
|
StreamInfo currentInfo;
|
||||||
@State
|
@State
|
||||||
|
@ -106,34 +86,25 @@ public class DownloadDialog extends DialogFragment
|
||||||
int selectedAudioIndex = 0; // default to the first item
|
int selectedAudioIndex = 0; // default to the first item
|
||||||
@State
|
@State
|
||||||
int selectedSubtitleIndex = 0; // default to the first item
|
int selectedSubtitleIndex = 0; // default to the first item
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private OnDismissListener onDismissListener = null;
|
private OnDismissListener onDismissListener = null;
|
||||||
|
|
||||||
private StoredDirectoryHelper mainStorageAudio = null;
|
private StoredDirectoryHelper mainStorageAudio = null;
|
||||||
private StoredDirectoryHelper mainStorageVideo = null;
|
private StoredDirectoryHelper mainStorageVideo = null;
|
||||||
private DownloadManager downloadManager = null;
|
private DownloadManager downloadManager = null;
|
||||||
private ActionMenuItemView okButton = null;
|
private ActionMenuItemView okButton = null;
|
||||||
private Context context;
|
private Context context;
|
||||||
private boolean askForSavePath;
|
private boolean askForSavePath;
|
||||||
|
|
||||||
private StreamItemAdapter<AudioStream, Stream> audioStreamsAdapter;
|
private StreamItemAdapter<AudioStream, Stream> audioStreamsAdapter;
|
||||||
private StreamItemAdapter<VideoStream, AudioStream> videoStreamsAdapter;
|
private StreamItemAdapter<VideoStream, AudioStream> videoStreamsAdapter;
|
||||||
private StreamItemAdapter<SubtitlesStream, Stream> subtitleStreamsAdapter;
|
private StreamItemAdapter<SubtitlesStream, Stream> subtitleStreamsAdapter;
|
||||||
|
|
||||||
private final CompositeDisposable disposables = new CompositeDisposable();
|
|
||||||
|
|
||||||
private DownloadDialogBinding dialogBinding;
|
private DownloadDialogBinding dialogBinding;
|
||||||
|
|
||||||
private SharedPreferences prefs;
|
|
||||||
|
|
||||||
// Variables for file name and MIME type when picking new folder because it's not set yet
|
|
||||||
private String filenameTmp;
|
|
||||||
private String mimeTmp;
|
|
||||||
|
|
||||||
private final ActivityResultLauncher<Intent> requestDownloadSaveAsLauncher =
|
private final ActivityResultLauncher<Intent> requestDownloadSaveAsLauncher =
|
||||||
registerForActivityResult(
|
registerForActivityResult(
|
||||||
new StartActivityForResult(), this::requestDownloadSaveAsResult);
|
new StartActivityForResult(), this::requestDownloadSaveAsResult);
|
||||||
|
private SharedPreferences prefs;
|
||||||
|
// Variables for file name and MIME type when picking new folder because it's not set yet
|
||||||
|
private String filenameTmp;
|
||||||
|
private String mimeTmp;
|
||||||
private final ActivityResultLauncher<Intent> requestDownloadPickAudioFolderLauncher =
|
private final ActivityResultLauncher<Intent> requestDownloadPickAudioFolderLauncher =
|
||||||
registerForActivityResult(
|
registerForActivityResult(
|
||||||
new StartActivityForResult(), this::requestDownloadPickAudioFolderResult);
|
new StartActivityForResult(), this::requestDownloadPickAudioFolderResult);
|
||||||
|
@ -1031,7 +1002,7 @@ public class DownloadDialog extends DialogFragment
|
||||||
|
|
||||||
if (selectedStream.getFormat() == MediaFormat.TTML) {
|
if (selectedStream.getFormat() == MediaFormat.TTML) {
|
||||||
psName = Postprocessing.ALGORITHM_TTML_CONVERTER;
|
psName = Postprocessing.ALGORITHM_TTML_CONVERTER;
|
||||||
psArgs = new String[] {
|
psArgs = new String[]{
|
||||||
selectedStream.getFormat().getSuffix(),
|
selectedStream.getFormat().getSuffix(),
|
||||||
"false" // ignore empty frames
|
"false" // ignore empty frames
|
||||||
};
|
};
|
||||||
|
@ -1042,10 +1013,10 @@ public class DownloadDialog extends DialogFragment
|
||||||
}
|
}
|
||||||
|
|
||||||
if (secondaryStream == null) {
|
if (secondaryStream == null) {
|
||||||
urls = new String[] {
|
urls = new String[]{
|
||||||
selectedStream.getContent()
|
selectedStream.getContent()
|
||||||
};
|
};
|
||||||
recoveryInfo = new MissionRecoveryInfo[] {
|
recoveryInfo = new MissionRecoveryInfo[]{
|
||||||
new MissionRecoveryInfo(selectedStream)
|
new MissionRecoveryInfo(selectedStream)
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
|
@ -1054,10 +1025,10 @@ public class DownloadDialog extends DialogFragment
|
||||||
+ secondaryStream.getDeliveryMethod());
|
+ secondaryStream.getDeliveryMethod());
|
||||||
}
|
}
|
||||||
|
|
||||||
urls = new String[] {
|
urls = new String[]{
|
||||||
selectedStream.getContent(), secondaryStream.getContent()
|
selectedStream.getContent(), secondaryStream.getContent()
|
||||||
};
|
};
|
||||||
recoveryInfo = new MissionRecoveryInfo[] {new MissionRecoveryInfo(selectedStream),
|
recoveryInfo = new MissionRecoveryInfo[]{new MissionRecoveryInfo(selectedStream),
|
||||||
new MissionRecoveryInfo(secondaryStream)};
|
new MissionRecoveryInfo(secondaryStream)};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,7 @@
|
||||||
package org.schabi.newpipe.error;
|
package org.schabi.newpipe.error;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
import org.acra.ReportField;
|
import org.acra.ReportField;
|
||||||
import org.acra.data.CrashReportData;
|
import org.acra.data.CrashReportData;
|
||||||
import org.acra.sender.ReportSender;
|
import org.acra.sender.ReportSender;
|
||||||
|
|
|
@ -1,11 +1,8 @@
|
||||||
package org.schabi.newpipe.error;
|
package org.schabi.newpipe.error;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
import com.google.auto.service.AutoService;
|
import com.google.auto.service.AutoService;
|
||||||
|
|
||||||
import org.acra.config.CoreConfiguration;
|
import org.acra.config.CoreConfiguration;
|
||||||
import org.acra.sender.ReportSender;
|
import org.acra.sender.ReportSender;
|
||||||
import org.acra.sender.ReportSenderFactory;
|
import org.acra.sender.ReportSenderFactory;
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
package org.schabi.newpipe.error;
|
package org.schabi.newpipe.error;
|
||||||
|
|
||||||
import static org.schabi.newpipe.util.Localization.assureCorrectAppLanguage;
|
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
@ -12,14 +10,11 @@ import android.util.Log;
|
||||||
import android.view.Menu;
|
import android.view.Menu;
|
||||||
import android.view.MenuInflater;
|
import android.view.MenuInflater;
|
||||||
import android.view.MenuItem;
|
import android.view.MenuItem;
|
||||||
|
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.appcompat.app.ActionBar;
|
import androidx.appcompat.app.ActionBar;
|
||||||
import androidx.appcompat.app.AlertDialog;
|
import androidx.appcompat.app.AlertDialog;
|
||||||
import androidx.appcompat.app.AppCompatActivity;
|
import androidx.appcompat.app.AppCompatActivity;
|
||||||
|
|
||||||
import com.grack.nanojson.JsonWriter;
|
import com.grack.nanojson.JsonWriter;
|
||||||
|
|
||||||
import org.schabi.newpipe.BuildConfig;
|
import org.schabi.newpipe.BuildConfig;
|
||||||
import org.schabi.newpipe.MainActivity;
|
import org.schabi.newpipe.MainActivity;
|
||||||
import org.schabi.newpipe.R;
|
import org.schabi.newpipe.R;
|
||||||
|
@ -33,6 +28,8 @@ import java.time.format.DateTimeFormatter;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import static org.schabi.newpipe.util.Localization.assureCorrectAppLanguage;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Created by Christian Schabesberger on 24.10.15.
|
* Created by Christian Schabesberger on 24.10.15.
|
||||||
*
|
*
|
||||||
|
@ -83,6 +80,25 @@ public class ErrorActivity extends AppCompatActivity {
|
||||||
// Activity lifecycle
|
// Activity lifecycle
|
||||||
////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the checked activity.
|
||||||
|
*
|
||||||
|
* @param returnActivity the activity to return to
|
||||||
|
* @return the casted return activity or null
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
static Class<? extends Activity> getReturnActivity(final Class<?> returnActivity) {
|
||||||
|
Class<? extends Activity> checkedReturnActivity = null;
|
||||||
|
if (returnActivity != null) {
|
||||||
|
if (Activity.class.isAssignableFrom(returnActivity)) {
|
||||||
|
checkedReturnActivity = returnActivity.asSubclass(Activity.class);
|
||||||
|
} else {
|
||||||
|
checkedReturnActivity = MainActivity.class;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return checkedReturnActivity;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(final Bundle savedInstanceState) {
|
protected void onCreate(final Bundle savedInstanceState) {
|
||||||
assureCorrectAppLanguage(this);
|
assureCorrectAppLanguage(this);
|
||||||
|
@ -188,25 +204,6 @@ public class ErrorActivity extends AppCompatActivity {
|
||||||
.collect(Collectors.joining(separator + "\n", separator + "\n", separator));
|
.collect(Collectors.joining(separator + "\n", separator + "\n", separator));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the checked activity.
|
|
||||||
*
|
|
||||||
* @param returnActivity the activity to return to
|
|
||||||
* @return the casted return activity or null
|
|
||||||
*/
|
|
||||||
@Nullable
|
|
||||||
static Class<? extends Activity> getReturnActivity(final Class<?> returnActivity) {
|
|
||||||
Class<? extends Activity> checkedReturnActivity = null;
|
|
||||||
if (returnActivity != null) {
|
|
||||||
if (Activity.class.isAssignableFrom(returnActivity)) {
|
|
||||||
checkedReturnActivity = returnActivity.asSubclass(Activity.class);
|
|
||||||
} else {
|
|
||||||
checkedReturnActivity = MainActivity.class;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return checkedReturnActivity;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void buildInfo(final ErrorInfo info) {
|
private void buildInfo(final ErrorInfo info) {
|
||||||
String text = "";
|
String text = "";
|
||||||
|
|
||||||
|
@ -267,7 +264,7 @@ public class ErrorActivity extends AppCompatActivity {
|
||||||
htmlErrorReport
|
htmlErrorReport
|
||||||
.append("## Exception")
|
.append("## Exception")
|
||||||
.append("\n* __User Action:__ ")
|
.append("\n* __User Action:__ ")
|
||||||
.append(getUserActionString(errorInfo.getUserAction()))
|
.append(getUserActionString(errorInfo.getUserAction()))
|
||||||
.append("\n* __Request:__ ").append(errorInfo.getRequest())
|
.append("\n* __Request:__ ").append(errorInfo.getRequest())
|
||||||
.append("\n* __Content Country:__ ").append(getContentCountryString())
|
.append("\n* __Content Country:__ ").append(getContentCountryString())
|
||||||
.append("\n* __Content Language:__ ").append(getContentLanguageString())
|
.append("\n* __Content Language:__ ").append(getContentLanguageString())
|
||||||
|
|
|
@ -7,19 +7,13 @@ import android.os.Bundle;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.Menu;
|
import android.view.Menu;
|
||||||
import android.view.MenuItem;
|
import android.view.MenuItem;
|
||||||
import android.webkit.CookieManager;
|
import android.webkit.*;
|
||||||
import android.webkit.WebResourceRequest;
|
|
||||||
import android.webkit.WebSettings;
|
|
||||||
import android.webkit.WebView;
|
|
||||||
import android.webkit.WebViewClient;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.appcompat.app.ActionBar;
|
import androidx.appcompat.app.ActionBar;
|
||||||
import androidx.appcompat.app.AppCompatActivity;
|
import androidx.appcompat.app.AppCompatActivity;
|
||||||
import androidx.core.app.NavUtils;
|
import androidx.core.app.NavUtils;
|
||||||
import androidx.preference.PreferenceManager;
|
import androidx.preference.PreferenceManager;
|
||||||
|
|
||||||
import org.schabi.newpipe.DownloaderImpl;
|
import org.schabi.newpipe.DownloaderImpl;
|
||||||
import org.schabi.newpipe.MainActivity;
|
import org.schabi.newpipe.MainActivity;
|
||||||
import org.schabi.newpipe.R;
|
import org.schabi.newpipe.R;
|
||||||
|
@ -54,6 +48,8 @@ public class ReCaptchaActivity extends AppCompatActivity {
|
||||||
public static final String TAG = ReCaptchaActivity.class.toString();
|
public static final String TAG = ReCaptchaActivity.class.toString();
|
||||||
public static final String YT_URL = "https://www.youtube.com";
|
public static final String YT_URL = "https://www.youtube.com";
|
||||||
public static final String RECAPTCHA_COOKIES_KEY = "recaptcha_cookies";
|
public static final String RECAPTCHA_COOKIES_KEY = "recaptcha_cookies";
|
||||||
|
private ActivityRecaptchaBinding recaptchaBinding;
|
||||||
|
private String foundCookies = "";
|
||||||
|
|
||||||
public static String sanitizeRecaptchaUrl(@Nullable final String url) {
|
public static String sanitizeRecaptchaUrl(@Nullable final String url) {
|
||||||
if (url == null || url.trim().isEmpty()) {
|
if (url == null || url.trim().isEmpty()) {
|
||||||
|
@ -64,9 +60,6 @@ public class ReCaptchaActivity extends AppCompatActivity {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private ActivityRecaptchaBinding recaptchaBinding;
|
|
||||||
private String foundCookies = "";
|
|
||||||
|
|
||||||
@SuppressLint("SetJavaScriptEnabled")
|
@SuppressLint("SetJavaScriptEnabled")
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(final Bundle savedInstanceState) {
|
protected void onCreate(final Bundle savedInstanceState) {
|
||||||
|
|
|
@ -4,11 +4,10 @@ import android.os.Bundle;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.widget.ProgressBar;
|
import android.widget.ProgressBar;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.fragment.app.Fragment;
|
import androidx.fragment.app.Fragment;
|
||||||
|
import icepick.State;
|
||||||
import org.schabi.newpipe.BaseFragment;
|
import org.schabi.newpipe.BaseFragment;
|
||||||
import org.schabi.newpipe.R;
|
import org.schabi.newpipe.R;
|
||||||
import org.schabi.newpipe.error.ErrorInfo;
|
import org.schabi.newpipe.error.ErrorInfo;
|
||||||
|
@ -18,24 +17,20 @@ import org.schabi.newpipe.util.InfoCache;
|
||||||
|
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
||||||
import icepick.State;
|
|
||||||
|
|
||||||
import static org.schabi.newpipe.ktx.ViewUtils.animate;
|
import static org.schabi.newpipe.ktx.ViewUtils.animate;
|
||||||
|
|
||||||
public abstract class BaseStateFragment<I> extends BaseFragment implements ViewContract<I> {
|
public abstract class BaseStateFragment<I> extends BaseFragment implements ViewContract<I> {
|
||||||
@State
|
@State
|
||||||
protected AtomicBoolean wasLoading = new AtomicBoolean();
|
protected AtomicBoolean wasLoading = new AtomicBoolean();
|
||||||
protected AtomicBoolean isLoading = new AtomicBoolean();
|
protected AtomicBoolean isLoading = new AtomicBoolean();
|
||||||
|
@Nullable
|
||||||
|
@State
|
||||||
|
protected ErrorInfo lastPanelError = null;
|
||||||
@Nullable
|
@Nullable
|
||||||
private View emptyStateView;
|
private View emptyStateView;
|
||||||
@Nullable
|
@Nullable
|
||||||
private ProgressBar loadingProgressBar;
|
private ProgressBar loadingProgressBar;
|
||||||
|
|
||||||
private ErrorPanelHelper errorPanelHelper;
|
private ErrorPanelHelper errorPanelHelper;
|
||||||
@Nullable
|
|
||||||
@State
|
|
||||||
protected ErrorInfo lastPanelError = null;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onViewCreated(@NonNull final View rootView, final Bundle savedInstanceState) {
|
public void onViewCreated(@NonNull final View rootView, final Bundle savedInstanceState) {
|
||||||
|
|
|
@ -4,9 +4,7 @@ import android.os.Bundle;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
import org.schabi.newpipe.BaseFragment;
|
import org.schabi.newpipe.BaseFragment;
|
||||||
import org.schabi.newpipe.R;
|
import org.schabi.newpipe.R;
|
||||||
|
|
||||||
|
|
|
@ -4,9 +4,7 @@ import android.os.Bundle;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
import org.schabi.newpipe.BaseFragment;
|
import org.schabi.newpipe.BaseFragment;
|
||||||
import org.schabi.newpipe.R;
|
import org.schabi.newpipe.R;
|
||||||
|
|
||||||
|
|
|
@ -3,13 +3,7 @@ package org.schabi.newpipe.fragments;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.LayoutInflater;
|
import android.view.*;
|
||||||
import android.view.Menu;
|
|
||||||
import android.view.MenuInflater;
|
|
||||||
import android.view.MenuItem;
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.ViewGroup;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.appcompat.app.ActionBar;
|
import androidx.appcompat.app.ActionBar;
|
||||||
|
@ -17,9 +11,7 @@ import androidx.fragment.app.Fragment;
|
||||||
import androidx.fragment.app.FragmentManager;
|
import androidx.fragment.app.FragmentManager;
|
||||||
import androidx.fragment.app.FragmentStatePagerAdapterMenuWorkaround;
|
import androidx.fragment.app.FragmentStatePagerAdapterMenuWorkaround;
|
||||||
import androidx.preference.PreferenceManager;
|
import androidx.preference.PreferenceManager;
|
||||||
|
|
||||||
import com.google.android.material.tabs.TabLayout;
|
import com.google.android.material.tabs.TabLayout;
|
||||||
|
|
||||||
import org.schabi.newpipe.BaseFragment;
|
import org.schabi.newpipe.BaseFragment;
|
||||||
import org.schabi.newpipe.R;
|
import org.schabi.newpipe.R;
|
||||||
import org.schabi.newpipe.databinding.FragmentMainBinding;
|
import org.schabi.newpipe.databinding.FragmentMainBinding;
|
||||||
|
@ -34,10 +26,9 @@ import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class MainFragment extends BaseFragment implements TabLayout.OnTabSelectedListener {
|
public class MainFragment extends BaseFragment implements TabLayout.OnTabSelectedListener {
|
||||||
|
private final List<Tab> tabsList = new ArrayList<>();
|
||||||
private FragmentMainBinding binding;
|
private FragmentMainBinding binding;
|
||||||
private SelectedTabsPagerAdapter pagerAdapter;
|
private SelectedTabsPagerAdapter pagerAdapter;
|
||||||
|
|
||||||
private final List<Tab> tabsList = new ArrayList<>();
|
|
||||||
private TabsManager tabsManager;
|
private TabsManager tabsManager;
|
||||||
|
|
||||||
private boolean hasTabsChanged = false;
|
private boolean hasTabsChanged = false;
|
||||||
|
@ -199,7 +190,8 @@ public class MainFragment extends BaseFragment implements TabLayout.OnTabSelecte
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onTabUnselected(final TabLayout.Tab tab) { }
|
public void onTabUnselected(final TabLayout.Tab tab) {
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onTabReselected(final TabLayout.Tab tab) {
|
public void onTabReselected(final TabLayout.Tab tab) {
|
||||||
|
|
|
@ -1,25 +1,18 @@
|
||||||
package org.schabi.newpipe.fragments.detail;
|
package org.schabi.newpipe.fragments.detail;
|
||||||
|
|
||||||
import static android.text.TextUtils.isEmpty;
|
|
||||||
import static org.schabi.newpipe.extractor.stream.StreamExtractor.NO_AGE_LIMIT;
|
|
||||||
import static org.schabi.newpipe.extractor.utils.Utils.isBlank;
|
|
||||||
import static org.schabi.newpipe.util.Localization.getAppLocale;
|
|
||||||
import static org.schabi.newpipe.util.text.TextLinkifier.SET_LINK_MOVEMENT_METHOD;
|
|
||||||
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.widget.LinearLayout;
|
import android.widget.LinearLayout;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.annotation.StringRes;
|
import androidx.annotation.StringRes;
|
||||||
import androidx.appcompat.widget.TooltipCompat;
|
import androidx.appcompat.widget.TooltipCompat;
|
||||||
import androidx.core.text.HtmlCompat;
|
import androidx.core.text.HtmlCompat;
|
||||||
|
|
||||||
import com.google.android.material.chip.Chip;
|
import com.google.android.material.chip.Chip;
|
||||||
|
import icepick.State;
|
||||||
|
import io.reactivex.rxjava3.disposables.CompositeDisposable;
|
||||||
import org.schabi.newpipe.BaseFragment;
|
import org.schabi.newpipe.BaseFragment;
|
||||||
import org.schabi.newpipe.R;
|
import org.schabi.newpipe.R;
|
||||||
import org.schabi.newpipe.databinding.FragmentDescriptionBinding;
|
import org.schabi.newpipe.databinding.FragmentDescriptionBinding;
|
||||||
|
@ -32,14 +25,17 @@ import org.schabi.newpipe.util.NavigationHelper;
|
||||||
import org.schabi.newpipe.util.external_communication.ShareUtils;
|
import org.schabi.newpipe.util.external_communication.ShareUtils;
|
||||||
import org.schabi.newpipe.util.text.TextLinkifier;
|
import org.schabi.newpipe.util.text.TextLinkifier;
|
||||||
|
|
||||||
import icepick.State;
|
import static android.text.TextUtils.isEmpty;
|
||||||
import io.reactivex.rxjava3.disposables.CompositeDisposable;
|
import static org.schabi.newpipe.extractor.stream.StreamExtractor.NO_AGE_LIMIT;
|
||||||
|
import static org.schabi.newpipe.extractor.utils.Utils.isBlank;
|
||||||
|
import static org.schabi.newpipe.util.Localization.getAppLocale;
|
||||||
|
import static org.schabi.newpipe.util.text.TextLinkifier.SET_LINK_MOVEMENT_METHOD;
|
||||||
|
|
||||||
public class DescriptionFragment extends BaseFragment {
|
public class DescriptionFragment extends BaseFragment {
|
||||||
|
|
||||||
|
final CompositeDisposable descriptionDisposables = new CompositeDisposable();
|
||||||
@State
|
@State
|
||||||
StreamInfo streamInfo = null;
|
StreamInfo streamInfo = null;
|
||||||
final CompositeDisposable descriptionDisposables = new CompositeDisposable();
|
|
||||||
FragmentDescriptionBinding binding;
|
FragmentDescriptionBinding binding;
|
||||||
|
|
||||||
public DescriptionFragment() {
|
public DescriptionFragment() {
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package org.schabi.newpipe.fragments.detail;
|
package org.schabi.newpipe.fragments.detail;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
import org.schabi.newpipe.player.playqueue.PlayQueue;
|
import org.schabi.newpipe.player.playqueue.PlayQueue;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
@ -20,14 +19,6 @@ class StackItem implements Serializable {
|
||||||
this.playQueue = playQueue;
|
this.playQueue = playQueue;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setUrl(final String url) {
|
|
||||||
this.url = url;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setPlayQueue(final PlayQueue queue) {
|
|
||||||
this.playQueue = queue;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getServiceId() {
|
public int getServiceId() {
|
||||||
return serviceId;
|
return serviceId;
|
||||||
}
|
}
|
||||||
|
@ -44,10 +35,18 @@ class StackItem implements Serializable {
|
||||||
return url;
|
return url;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setUrl(final String url) {
|
||||||
|
this.url = url;
|
||||||
|
}
|
||||||
|
|
||||||
public PlayQueue getPlayQueue() {
|
public PlayQueue getPlayQueue() {
|
||||||
return playQueue;
|
return playQueue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setPlayQueue(final PlayQueue queue) {
|
||||||
|
this.playQueue = queue;
|
||||||
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package org.schabi.newpipe.fragments.detail;
|
package org.schabi.newpipe.fragments.detail;
|
||||||
|
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.fragment.app.Fragment;
|
import androidx.fragment.app.Fragment;
|
||||||
|
|
|
@ -1,26 +1,9 @@
|
||||||
package org.schabi.newpipe.fragments.detail;
|
package org.schabi.newpipe.fragments.detail;
|
||||||
|
|
||||||
import static android.text.TextUtils.isEmpty;
|
|
||||||
import static org.schabi.newpipe.extractor.StreamingService.ServiceInfo.MediaCapability.COMMENTS;
|
|
||||||
import static org.schabi.newpipe.extractor.stream.StreamExtractor.NO_AGE_LIMIT;
|
|
||||||
import static org.schabi.newpipe.ktx.ViewUtils.animate;
|
|
||||||
import static org.schabi.newpipe.ktx.ViewUtils.animateRotation;
|
|
||||||
import static org.schabi.newpipe.player.helper.PlayerHelper.globalScreenOrientationLocked;
|
|
||||||
import static org.schabi.newpipe.player.helper.PlayerHelper.isClearingQueueConfirmationRequired;
|
|
||||||
import static org.schabi.newpipe.player.playqueue.PlayQueueItem.RECOVERY_UNSET;
|
|
||||||
import static org.schabi.newpipe.util.ExtractorHelper.showMetaInfoInTextView;
|
|
||||||
import static org.schabi.newpipe.util.ListHelper.getUrlAndNonTorrentStreams;
|
|
||||||
import static org.schabi.newpipe.util.NavigationHelper.openPlayQueue;
|
|
||||||
import static org.schabi.newpipe.util.NavigationHelper.playWithKore;
|
|
||||||
|
|
||||||
import android.animation.ValueAnimator;
|
import android.animation.ValueAnimator;
|
||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.content.BroadcastReceiver;
|
import android.content.*;
|
||||||
import android.content.Context;
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.content.IntentFilter;
|
|
||||||
import android.content.SharedPreferences;
|
|
||||||
import android.content.pm.ActivityInfo;
|
import android.content.pm.ActivityInfo;
|
||||||
import android.database.ContentObserver;
|
import android.database.ContentObserver;
|
||||||
import android.graphics.Color;
|
import android.graphics.Color;
|
||||||
|
@ -34,17 +17,11 @@ import android.provider.Settings;
|
||||||
import android.util.DisplayMetrics;
|
import android.util.DisplayMetrics;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.util.TypedValue;
|
import android.util.TypedValue;
|
||||||
import android.view.LayoutInflater;
|
import android.view.*;
|
||||||
import android.view.MotionEvent;
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.ViewGroup;
|
|
||||||
import android.view.ViewTreeObserver;
|
|
||||||
import android.view.WindowManager;
|
|
||||||
import android.view.animation.DecelerateInterpolator;
|
import android.view.animation.DecelerateInterpolator;
|
||||||
import android.widget.FrameLayout;
|
import android.widget.FrameLayout;
|
||||||
import android.widget.RelativeLayout;
|
import android.widget.RelativeLayout;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import androidx.annotation.AttrRes;
|
import androidx.annotation.AttrRes;
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
@ -58,14 +35,17 @@ import androidx.core.view.WindowCompat;
|
||||||
import androidx.core.view.WindowInsetsCompat;
|
import androidx.core.view.WindowInsetsCompat;
|
||||||
import androidx.core.view.WindowInsetsControllerCompat;
|
import androidx.core.view.WindowInsetsControllerCompat;
|
||||||
import androidx.preference.PreferenceManager;
|
import androidx.preference.PreferenceManager;
|
||||||
|
|
||||||
import com.google.android.exoplayer2.PlaybackException;
|
import com.google.android.exoplayer2.PlaybackException;
|
||||||
import com.google.android.exoplayer2.PlaybackParameters;
|
import com.google.android.exoplayer2.PlaybackParameters;
|
||||||
import com.google.android.material.appbar.AppBarLayout;
|
import com.google.android.material.appbar.AppBarLayout;
|
||||||
import com.google.android.material.bottomsheet.BottomSheetBehavior;
|
import com.google.android.material.bottomsheet.BottomSheetBehavior;
|
||||||
import com.google.android.material.tabs.TabLayout;
|
import com.google.android.material.tabs.TabLayout;
|
||||||
import com.squareup.picasso.Callback;
|
import com.squareup.picasso.Callback;
|
||||||
|
import icepick.State;
|
||||||
|
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
|
||||||
|
import io.reactivex.rxjava3.disposables.CompositeDisposable;
|
||||||
|
import io.reactivex.rxjava3.disposables.Disposable;
|
||||||
|
import io.reactivex.rxjava3.schedulers.Schedulers;
|
||||||
import org.schabi.newpipe.App;
|
import org.schabi.newpipe.App;
|
||||||
import org.schabi.newpipe.R;
|
import org.schabi.newpipe.R;
|
||||||
import org.schabi.newpipe.database.stream.model.StreamEntity;
|
import org.schabi.newpipe.database.stream.model.StreamEntity;
|
||||||
|
@ -79,11 +59,7 @@ import org.schabi.newpipe.extractor.InfoItem;
|
||||||
import org.schabi.newpipe.extractor.NewPipe;
|
import org.schabi.newpipe.extractor.NewPipe;
|
||||||
import org.schabi.newpipe.extractor.exceptions.ContentNotSupportedException;
|
import org.schabi.newpipe.extractor.exceptions.ContentNotSupportedException;
|
||||||
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
|
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
|
||||||
import org.schabi.newpipe.extractor.stream.AudioStream;
|
import org.schabi.newpipe.extractor.stream.*;
|
||||||
import org.schabi.newpipe.extractor.stream.Stream;
|
|
||||||
import org.schabi.newpipe.extractor.stream.StreamInfo;
|
|
||||||
import org.schabi.newpipe.extractor.stream.StreamType;
|
|
||||||
import org.schabi.newpipe.extractor.stream.VideoStream;
|
|
||||||
import org.schabi.newpipe.fragments.BackPressable;
|
import org.schabi.newpipe.fragments.BackPressable;
|
||||||
import org.schabi.newpipe.fragments.BaseStateFragment;
|
import org.schabi.newpipe.fragments.BaseStateFragment;
|
||||||
import org.schabi.newpipe.fragments.EmptyFragment;
|
import org.schabi.newpipe.fragments.EmptyFragment;
|
||||||
|
@ -104,33 +80,26 @@ import org.schabi.newpipe.player.playqueue.PlayQueueItem;
|
||||||
import org.schabi.newpipe.player.playqueue.SinglePlayQueue;
|
import org.schabi.newpipe.player.playqueue.SinglePlayQueue;
|
||||||
import org.schabi.newpipe.player.ui.MainPlayerUi;
|
import org.schabi.newpipe.player.ui.MainPlayerUi;
|
||||||
import org.schabi.newpipe.player.ui.VideoPlayerUi;
|
import org.schabi.newpipe.player.ui.VideoPlayerUi;
|
||||||
import org.schabi.newpipe.util.Constants;
|
import org.schabi.newpipe.util.*;
|
||||||
import org.schabi.newpipe.util.DeviceUtils;
|
|
||||||
import org.schabi.newpipe.util.ExtractorHelper;
|
|
||||||
import org.schabi.newpipe.util.ListHelper;
|
|
||||||
import org.schabi.newpipe.util.Localization;
|
|
||||||
import org.schabi.newpipe.util.NavigationHelper;
|
|
||||||
import org.schabi.newpipe.util.PermissionHelper;
|
|
||||||
import org.schabi.newpipe.util.PicassoHelper;
|
|
||||||
import org.schabi.newpipe.util.StreamTypeUtil;
|
|
||||||
import org.schabi.newpipe.util.ThemeHelper;
|
|
||||||
import org.schabi.newpipe.util.external_communication.KoreUtils;
|
import org.schabi.newpipe.util.external_communication.KoreUtils;
|
||||||
import org.schabi.newpipe.util.external_communication.ShareUtils;
|
import org.schabi.newpipe.util.external_communication.ShareUtils;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.LinkedList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.Optional;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
import icepick.State;
|
import static android.text.TextUtils.isEmpty;
|
||||||
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
|
import static org.schabi.newpipe.extractor.StreamingService.ServiceInfo.MediaCapability.COMMENTS;
|
||||||
import io.reactivex.rxjava3.disposables.CompositeDisposable;
|
import static org.schabi.newpipe.extractor.stream.StreamExtractor.NO_AGE_LIMIT;
|
||||||
import io.reactivex.rxjava3.disposables.Disposable;
|
import static org.schabi.newpipe.ktx.ViewUtils.animate;
|
||||||
import io.reactivex.rxjava3.schedulers.Schedulers;
|
import static org.schabi.newpipe.ktx.ViewUtils.animateRotation;
|
||||||
|
import static org.schabi.newpipe.player.helper.PlayerHelper.globalScreenOrientationLocked;
|
||||||
|
import static org.schabi.newpipe.player.helper.PlayerHelper.isClearingQueueConfirmationRequired;
|
||||||
|
import static org.schabi.newpipe.player.playqueue.PlayQueueItem.RECOVERY_UNSET;
|
||||||
|
import static org.schabi.newpipe.util.ExtractorHelper.showMetaInfoInTextView;
|
||||||
|
import static org.schabi.newpipe.util.ListHelper.getUrlAndNonTorrentStreams;
|
||||||
|
import static org.schabi.newpipe.util.NavigationHelper.openPlayQueue;
|
||||||
|
import static org.schabi.newpipe.util.NavigationHelper.playWithKore;
|
||||||
|
|
||||||
public final class VideoDetailFragment
|
public final class VideoDetailFragment
|
||||||
extends BaseStateFragment<StreamInfo>
|
extends BaseStateFragment<StreamInfo>
|
||||||
|
@ -138,10 +107,6 @@ public final class VideoDetailFragment
|
||||||
PlayerServiceExtendedEventListener,
|
PlayerServiceExtendedEventListener,
|
||||||
OnKeyDownListener {
|
OnKeyDownListener {
|
||||||
public static final String KEY_SWITCHING_PLAYERS = "switching_players";
|
public static final String KEY_SWITCHING_PLAYERS = "switching_players";
|
||||||
|
|
||||||
private static final float MAX_OVERLAY_ALPHA = 0.9f;
|
|
||||||
private static final float MAX_PLAYER_HEIGHT = 0.7f;
|
|
||||||
|
|
||||||
public static final String ACTION_SHOW_MAIN_PLAYER =
|
public static final String ACTION_SHOW_MAIN_PLAYER =
|
||||||
App.PACKAGE_NAME + ".VideoDetailFragment.ACTION_SHOW_MAIN_PLAYER";
|
App.PACKAGE_NAME + ".VideoDetailFragment.ACTION_SHOW_MAIN_PLAYER";
|
||||||
public static final String ACTION_HIDE_MAIN_PLAYER =
|
public static final String ACTION_HIDE_MAIN_PLAYER =
|
||||||
|
@ -152,24 +117,50 @@ public final class VideoDetailFragment
|
||||||
App.PACKAGE_NAME + ".VideoDetailFragment.ACTION_VIDEO_FRAGMENT_RESUMED";
|
App.PACKAGE_NAME + ".VideoDetailFragment.ACTION_VIDEO_FRAGMENT_RESUMED";
|
||||||
public static final String ACTION_VIDEO_FRAGMENT_STOPPED =
|
public static final String ACTION_VIDEO_FRAGMENT_STOPPED =
|
||||||
App.PACKAGE_NAME + ".VideoDetailFragment.ACTION_VIDEO_FRAGMENT_STOPPED";
|
App.PACKAGE_NAME + ".VideoDetailFragment.ACTION_VIDEO_FRAGMENT_STOPPED";
|
||||||
|
private static final float MAX_OVERLAY_ALPHA = 0.9f;
|
||||||
|
private static final float MAX_PLAYER_HEIGHT = 0.7f;
|
||||||
private static final String COMMENTS_TAB_TAG = "COMMENTS";
|
private static final String COMMENTS_TAB_TAG = "COMMENTS";
|
||||||
private static final String RELATED_TAB_TAG = "NEXT VIDEO";
|
private static final String RELATED_TAB_TAG = "NEXT VIDEO";
|
||||||
private static final String DESCRIPTION_TAB_TAG = "DESCRIPTION TAB";
|
private static final String DESCRIPTION_TAB_TAG = "DESCRIPTION TAB";
|
||||||
private static final String EMPTY_TAB_TAG = "EMPTY TAB";
|
private static final String EMPTY_TAB_TAG = "EMPTY TAB";
|
||||||
|
|
||||||
private static final String PICASSO_VIDEO_DETAILS_TAG = "PICASSO_VIDEO_DETAILS_TAG";
|
private static final String PICASSO_VIDEO_DETAILS_TAG = "PICASSO_VIDEO_DETAILS_TAG";
|
||||||
|
/**
|
||||||
|
* Stack that contains the "navigation history".<br>
|
||||||
|
* The peek is the current video.
|
||||||
|
*/
|
||||||
|
private static LinkedList<StackItem> stack = new LinkedList<>();
|
||||||
|
@AttrRes
|
||||||
|
@NonNull
|
||||||
|
final List<Integer> tabIcons = new ArrayList<>();
|
||||||
|
@StringRes
|
||||||
|
@NonNull
|
||||||
|
final List<Integer> tabContentDescriptions = new ArrayList<>();
|
||||||
|
@NonNull
|
||||||
|
private final CompositeDisposable disposables = new CompositeDisposable();
|
||||||
|
private final PlayerHolder playerHolder = PlayerHolder.getInstance();
|
||||||
|
@State
|
||||||
|
private int serviceId = Constants.NO_SERVICE_ID;
|
||||||
|
@State
|
||||||
|
@NonNull
|
||||||
|
private String title = "";
|
||||||
|
@State
|
||||||
|
@Nullable
|
||||||
|
private String url = null;
|
||||||
|
@Nullable
|
||||||
|
private PlayQueue playQueue = null;
|
||||||
|
@State
|
||||||
|
private boolean autoPlayEnabled = true;
|
||||||
|
@State
|
||||||
|
int bottomSheetState = BottomSheetBehavior.STATE_EXPANDED;
|
||||||
|
@State
|
||||||
|
int lastStableBottomSheetState = BottomSheetBehavior.STATE_EXPANDED;
|
||||||
// tabs
|
// tabs
|
||||||
private boolean showComments;
|
private boolean showComments;
|
||||||
private boolean showRelatedItems;
|
private boolean showRelatedItems;
|
||||||
private boolean showDescription;
|
private boolean showDescription;
|
||||||
private String selectedTabTag;
|
private String selectedTabTag;
|
||||||
@AttrRes @NonNull final List<Integer> tabIcons = new ArrayList<>();
|
|
||||||
@StringRes @NonNull final List<Integer> tabContentDescriptions = new ArrayList<>();
|
|
||||||
private boolean tabSettingsChanged = false;
|
private boolean tabSettingsChanged = false;
|
||||||
private int lastAppBarVerticalOffset = Integer.MAX_VALUE; // prevents useless updates
|
|
||||||
|
|
||||||
private final SharedPreferences.OnSharedPreferenceChangeListener preferenceChangeListener =
|
private final SharedPreferences.OnSharedPreferenceChangeListener preferenceChangeListener =
|
||||||
(sharedPreferences, key) -> {
|
(sharedPreferences, key) -> {
|
||||||
if (getString(R.string.show_comments_key).equals(key)) {
|
if (getString(R.string.show_comments_key).equals(key)) {
|
||||||
|
@ -183,49 +174,43 @@ public final class VideoDetailFragment
|
||||||
tabSettingsChanged = true;
|
tabSettingsChanged = true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
private int lastAppBarVerticalOffset = Integer.MAX_VALUE; // prevents useless updates
|
||||||
@State
|
|
||||||
protected int serviceId = Constants.NO_SERVICE_ID;
|
|
||||||
@State
|
|
||||||
@NonNull
|
|
||||||
protected String title = "";
|
|
||||||
@State
|
|
||||||
@Nullable
|
|
||||||
protected String url = null;
|
|
||||||
@Nullable
|
|
||||||
protected PlayQueue playQueue = null;
|
|
||||||
@State
|
|
||||||
int bottomSheetState = BottomSheetBehavior.STATE_EXPANDED;
|
|
||||||
@State
|
|
||||||
int lastStableBottomSheetState = BottomSheetBehavior.STATE_EXPANDED;
|
|
||||||
@State
|
|
||||||
protected boolean autoPlayEnabled = true;
|
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private StreamInfo currentInfo = null;
|
private StreamInfo currentInfo = null;
|
||||||
private Disposable currentWorker;
|
private Disposable currentWorker;
|
||||||
@NonNull
|
|
||||||
private final CompositeDisposable disposables = new CompositeDisposable();
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private Disposable positionSubscriber = null;
|
private Disposable positionSubscriber = null;
|
||||||
|
|
||||||
private BottomSheetBehavior<FrameLayout> bottomSheetBehavior;
|
private BottomSheetBehavior<FrameLayout> bottomSheetBehavior;
|
||||||
private BottomSheetBehavior.BottomSheetCallback bottomSheetCallback;
|
|
||||||
private BroadcastReceiver broadcastReceiver;
|
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
// Views
|
// Views
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
private BottomSheetBehavior.BottomSheetCallback bottomSheetCallback;
|
||||||
|
private BroadcastReceiver broadcastReceiver;
|
||||||
private FragmentVideoDetailBinding binding;
|
private FragmentVideoDetailBinding binding;
|
||||||
|
|
||||||
private TabAdapter pageAdapter;
|
private TabAdapter pageAdapter;
|
||||||
|
|
||||||
private ContentObserver settingsContentObserver;
|
private ContentObserver settingsContentObserver;
|
||||||
@Nullable
|
@Nullable
|
||||||
private PlayerService playerService;
|
private PlayerService playerService;
|
||||||
private Player player;
|
private Player player;
|
||||||
private final PlayerHolder playerHolder = PlayerHolder.getInstance();
|
|
||||||
|
public static VideoDetailFragment getInstance(final int serviceId,
|
||||||
|
@Nullable final String videoUrl,
|
||||||
|
@NonNull final String name,
|
||||||
|
@Nullable final PlayQueue queue) {
|
||||||
|
final VideoDetailFragment instance = new VideoDetailFragment();
|
||||||
|
instance.setInitialData(serviceId, videoUrl, name, queue);
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
|
public static VideoDetailFragment getInstanceInCollapsedState() {
|
||||||
|
final VideoDetailFragment instance = new VideoDetailFragment();
|
||||||
|
instance.updateBottomSheetState(BottomSheetBehavior.STATE_COLLAPSED);
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
// Service management
|
// Service management
|
||||||
|
@ -267,6 +252,11 @@ public final class VideoDetailFragment
|
||||||
updateOverlayPlayQueueButtonVisibility();
|
updateOverlayPlayQueueButtonVisibility();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
|
// Fragment's Lifecycle
|
||||||
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onServiceDisconnected() {
|
public void onServiceDisconnected() {
|
||||||
playerService = null;
|
playerService = null;
|
||||||
|
@ -274,29 +264,6 @@ public final class VideoDetailFragment
|
||||||
restoreDefaultBrightness();
|
restoreDefaultBrightness();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*////////////////////////////////////////////////////////////////////////*/
|
|
||||||
|
|
||||||
public static VideoDetailFragment getInstance(final int serviceId,
|
|
||||||
@Nullable final String videoUrl,
|
|
||||||
@NonNull final String name,
|
|
||||||
@Nullable final PlayQueue queue) {
|
|
||||||
final VideoDetailFragment instance = new VideoDetailFragment();
|
|
||||||
instance.setInitialData(serviceId, videoUrl, name, queue);
|
|
||||||
return instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static VideoDetailFragment getInstanceInCollapsedState() {
|
|
||||||
final VideoDetailFragment instance = new VideoDetailFragment();
|
|
||||||
instance.updateBottomSheetState(BottomSheetBehavior.STATE_COLLAPSED);
|
|
||||||
return instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
|
||||||
// Fragment's Lifecycle
|
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(final Bundle savedInstanceState) {
|
public void onCreate(final Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
@ -422,28 +389,25 @@ public final class VideoDetailFragment
|
||||||
binding = null;
|
binding = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onActivityResult(final int requestCode, final int resultCode, final Intent data) {
|
|
||||||
super.onActivityResult(requestCode, resultCode, data);
|
|
||||||
switch (requestCode) {
|
|
||||||
case ReCaptchaActivity.RECAPTCHA_REQUEST:
|
|
||||||
if (resultCode == Activity.RESULT_OK) {
|
|
||||||
NavigationHelper.openVideoDetailFragment(requireContext(), getFM(),
|
|
||||||
serviceId, url, title, null, false);
|
|
||||||
} else {
|
|
||||||
Log.e(TAG, "ReCaptcha failed");
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
Log.e(TAG, "Request code from activity not supported [" + requestCode + "]");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
// OnClick
|
// OnClick
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onActivityResult(final int requestCode, final int resultCode, final Intent data) {
|
||||||
|
super.onActivityResult(requestCode, resultCode, data);
|
||||||
|
if (requestCode == ReCaptchaActivity.RECAPTCHA_REQUEST) {
|
||||||
|
if (resultCode == Activity.RESULT_OK) {
|
||||||
|
NavigationHelper.openVideoDetailFragment(requireContext(), getFM(),
|
||||||
|
serviceId, url, title, null, false);
|
||||||
|
} else {
|
||||||
|
Log.e(TAG, "ReCaptcha failed");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Log.e(TAG, "Request code from activity not supported [" + requestCode + "]");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void setOnClickListeners() {
|
private void setOnClickListeners() {
|
||||||
binding.detailTitleRootLayout.setOnClickListener(v -> toggleTitleAndSecondaryControls());
|
binding.detailTitleRootLayout.setOnClickListener(v -> toggleTitleAndSecondaryControls());
|
||||||
binding.detailUploaderRootLayout.setOnClickListener(makeOnClickListener(info -> {
|
binding.detailUploaderRootLayout.setOnClickListener(makeOnClickListener(info -> {
|
||||||
|
@ -574,6 +538,10 @@ public final class VideoDetailFragment
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
|
// Init
|
||||||
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
private void toggleTitleAndSecondaryControls() {
|
private void toggleTitleAndSecondaryControls() {
|
||||||
if (binding.detailSecondaryControlPanel.getVisibility() == View.GONE) {
|
if (binding.detailSecondaryControlPanel.getVisibility() == View.GONE) {
|
||||||
binding.detailVideoTitleView.setMaxLines(10);
|
binding.detailVideoTitleView.setMaxLines(10);
|
||||||
|
@ -590,10 +558,6 @@ public final class VideoDetailFragment
|
||||||
updateTabLayoutVisibility();
|
updateTabLayoutVisibility();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
|
||||||
// Init
|
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
|
||||||
|
|
||||||
@Override // called from onViewCreated in {@link BaseFragment#onViewCreated}
|
@Override // called from onViewCreated in {@link BaseFragment#onViewCreated}
|
||||||
protected void initViews(final View rootView, final Bundle savedInstanceState) {
|
protected void initViews(final View rootView, final Bundle savedInstanceState) {
|
||||||
super.initViews(rootView, savedInstanceState);
|
super.initViews(rootView, savedInstanceState);
|
||||||
|
@ -628,7 +592,7 @@ public final class VideoDetailFragment
|
||||||
|
|
||||||
final View.OnTouchListener controlsTouchListener = (view, motionEvent) -> {
|
final View.OnTouchListener controlsTouchListener = (view, motionEvent) -> {
|
||||||
if (motionEvent.getAction() == MotionEvent.ACTION_DOWN
|
if (motionEvent.getAction() == MotionEvent.ACTION_DOWN
|
||||||
&& PreferenceManager.getDefaultSharedPreferences(activity)
|
&& PreferenceManager.getDefaultSharedPreferences(activity)
|
||||||
.getBoolean(getString(R.string.show_hold_to_append_key), true)) {
|
.getBoolean(getString(R.string.show_hold_to_append_key), true)) {
|
||||||
|
|
||||||
animate(binding.touchAppendDetail, true, 250, AnimationType.ALPHA, 0, () ->
|
animate(binding.touchAppendDetail, true, 250, AnimationType.ALPHA, 0, () ->
|
||||||
|
@ -656,6 +620,10 @@ public final class VideoDetailFragment
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
|
// OwnStack
|
||||||
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
private void initThumbnailViews(@NonNull final StreamInfo info) {
|
private void initThumbnailViews(@NonNull final StreamInfo info) {
|
||||||
PicassoHelper.loadDetailsThumbnail(info.getThumbnailUrl()).tag(PICASSO_VIDEO_DETAILS_TAG)
|
PicassoHelper.loadDetailsThumbnail(info.getThumbnailUrl()).tag(PICASSO_VIDEO_DETAILS_TAG)
|
||||||
.into(binding.detailThumbnailImageView, new Callback() {
|
.into(binding.detailThumbnailImageView, new Callback() {
|
||||||
|
@ -677,16 +645,6 @@ public final class VideoDetailFragment
|
||||||
.into(binding.detailUploaderThumbnailView);
|
.into(binding.detailUploaderThumbnailView);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
|
||||||
// OwnStack
|
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Stack that contains the "navigation history".<br>
|
|
||||||
* The peek is the current video.
|
|
||||||
*/
|
|
||||||
private static LinkedList<StackItem> stack = new LinkedList<>();
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onKeyDown(final int keyCode) {
|
public boolean onKeyDown(final int keyCode) {
|
||||||
return isPlayerAvailable()
|
return isPlayerAvailable()
|
||||||
|
@ -817,7 +775,7 @@ public final class VideoDetailFragment
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void prepareAndLoadInfo() {
|
private void prepareAndLoadInfo() {
|
||||||
scrollToTop();
|
scrollToTop();
|
||||||
startLoading(false);
|
startLoading(false);
|
||||||
}
|
}
|
||||||
|
@ -1286,23 +1244,6 @@ public final class VideoDetailFragment
|
||||||
binding.playerPlaceholder.requestLayout();
|
binding.playerPlaceholder.requestLayout();
|
||||||
}
|
}
|
||||||
|
|
||||||
private final ViewTreeObserver.OnPreDrawListener preDrawListener =
|
|
||||||
new ViewTreeObserver.OnPreDrawListener() {
|
|
||||||
@Override
|
|
||||||
public boolean onPreDraw() {
|
|
||||||
final DisplayMetrics metrics = getResources().getDisplayMetrics();
|
|
||||||
|
|
||||||
if (getView() != null) {
|
|
||||||
final int height = (DeviceUtils.isInMultiWindow(activity)
|
|
||||||
? requireView()
|
|
||||||
: activity.getWindow().getDecorView()).getHeight();
|
|
||||||
setHeightThumbnail(height, metrics);
|
|
||||||
getView().getViewTreeObserver().removeOnPreDrawListener(preDrawListener);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method which controls the size of thumbnail and the size of main player inside
|
* Method which controls the size of thumbnail and the size of main player inside
|
||||||
* a layout with thumbnail. It decides what height the player should have in both
|
* a layout with thumbnail. It decides what height the player should have in both
|
||||||
|
@ -1331,7 +1272,22 @@ public final class VideoDetailFragment
|
||||||
: metrics.heightPixels / 2.0f);
|
: metrics.heightPixels / 2.0f);
|
||||||
setHeightThumbnail(height, metrics);
|
setHeightThumbnail(height, metrics);
|
||||||
}
|
}
|
||||||
}
|
} private final ViewTreeObserver.OnPreDrawListener preDrawListener =
|
||||||
|
new ViewTreeObserver.OnPreDrawListener() {
|
||||||
|
@Override
|
||||||
|
public boolean onPreDraw() {
|
||||||
|
final DisplayMetrics metrics = getResources().getDisplayMetrics();
|
||||||
|
|
||||||
|
if (getView() != null) {
|
||||||
|
final int height = (DeviceUtils.isInMultiWindow(activity)
|
||||||
|
? requireView()
|
||||||
|
: activity.getWindow().getDecorView()).getHeight();
|
||||||
|
setHeightThumbnail(height, metrics);
|
||||||
|
getView().getViewTreeObserver().removeOnPreDrawListener(preDrawListener);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
private void setHeightThumbnail(final int newHeight, final DisplayMetrics metrics) {
|
private void setHeightThumbnail(final int newHeight, final DisplayMetrics metrics) {
|
||||||
binding.detailThumbnailImageView.setLayoutParams(
|
binding.detailThumbnailImageView.setLayoutParams(
|
||||||
|
@ -1350,10 +1306,10 @@ public final class VideoDetailFragment
|
||||||
binding.detailContentRootHiding.setVisibility(View.VISIBLE);
|
binding.detailContentRootHiding.setVisibility(View.VISIBLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void setInitialData(final int newServiceId,
|
private void setInitialData(final int newServiceId,
|
||||||
@Nullable final String newUrl,
|
@Nullable final String newUrl,
|
||||||
@NonNull final String newTitle,
|
@NonNull final String newTitle,
|
||||||
@Nullable final PlayQueue newPlayQueue) {
|
@Nullable final PlayQueue newPlayQueue) {
|
||||||
this.serviceId = newServiceId;
|
this.serviceId = newServiceId;
|
||||||
this.url = newUrl;
|
this.url = newUrl;
|
||||||
this.title = newTitle;
|
this.title = newTitle;
|
||||||
|
@ -1422,11 +1378,6 @@ public final class VideoDetailFragment
|
||||||
activity.registerReceiver(broadcastReceiver, intentFilter);
|
activity.registerReceiver(broadcastReceiver, intentFilter);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
|
||||||
// Orientation listener
|
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
|
||||||
|
|
||||||
private void restoreDefaultOrientation() {
|
private void restoreDefaultOrientation() {
|
||||||
if (isPlayerAvailable() && player.videoPlayerSelected()) {
|
if (isPlayerAvailable() && player.videoPlayerSelected()) {
|
||||||
toggleFullscreenIfInFullscreenMode();
|
toggleFullscreenIfInFullscreenMode();
|
||||||
|
@ -1441,8 +1392,9 @@ public final class VideoDetailFragment
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
// Contract
|
// Orientation listener
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -1482,6 +1434,10 @@ public final class VideoDetailFragment
|
||||||
binding.detailSubChannelThumbnailView.setImageBitmap(null);
|
binding.detailSubChannelThumbnailView.setImageBitmap(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
|
// Contract
|
||||||
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handleResult(@NonNull final StreamInfo info) {
|
public void handleResult(@NonNull final StreamInfo info) {
|
||||||
super.handleResult(info);
|
super.handleResult(info);
|
||||||
|
@ -1670,10 +1626,6 @@ public final class VideoDetailFragment
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
|
||||||
// Stream Results
|
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
|
||||||
|
|
||||||
private void updateProgressInfo(@NonNull final StreamInfo info) {
|
private void updateProgressInfo(@NonNull final StreamInfo info) {
|
||||||
if (positionSubscriber != null) {
|
if (positionSubscriber != null) {
|
||||||
positionSubscriber.dispose();
|
positionSubscriber.dispose();
|
||||||
|
@ -1726,6 +1678,10 @@ public final class VideoDetailFragment
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
|
// Stream Results
|
||||||
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
private void showPlaybackProgress(final long progress, final long duration) {
|
private void showPlaybackProgress(final long progress, final long duration) {
|
||||||
final int progressSeconds = (int) TimeUnit.MILLISECONDS.toSeconds(progress);
|
final int progressSeconds = (int) TimeUnit.MILLISECONDS.toSeconds(progress);
|
||||||
final int durationSeconds = (int) TimeUnit.MILLISECONDS.toSeconds(duration);
|
final int durationSeconds = (int) TimeUnit.MILLISECONDS.toSeconds(duration);
|
||||||
|
@ -1749,15 +1705,15 @@ public final class VideoDetailFragment
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
|
||||||
// Player event listener
|
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onViewCreated() {
|
public void onViewCreated() {
|
||||||
tryAddVideoPlayerView();
|
tryAddVideoPlayerView();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
|
// Player event listener
|
||||||
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onQueueUpdate(final PlayQueue queue) {
|
public void onQueueUpdate(final PlayQueue queue) {
|
||||||
playQueue = queue;
|
playQueue = queue;
|
||||||
|
@ -1806,16 +1762,14 @@ public final class VideoDetailFragment
|
||||||
final PlaybackParameters parameters) {
|
final PlaybackParameters parameters) {
|
||||||
setOverlayPlayPauseImage(player != null && player.isPlaying());
|
setOverlayPlayPauseImage(player != null && player.isPlaying());
|
||||||
|
|
||||||
switch (state) {
|
if (state == Player.STATE_PLAYING) {
|
||||||
case Player.STATE_PLAYING:
|
if (binding.positionView.getAlpha() != 1.0f
|
||||||
if (binding.positionView.getAlpha() != 1.0f
|
&& player.getPlayQueue() != null
|
||||||
&& player.getPlayQueue() != null
|
&& player.getPlayQueue().getItem() != null
|
||||||
&& player.getPlayQueue().getItem() != null
|
&& player.getPlayQueue().getItem().getUrl().equals(url)) {
|
||||||
&& player.getPlayQueue().getItem().getUrl().equals(url)) {
|
animate(binding.positionView, true, 100);
|
||||||
animate(binding.positionView, true, 100);
|
animate(binding.detailPositionView, true, 100);
|
||||||
animate(binding.detailPositionView, true, 100);
|
}
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1948,10 +1902,6 @@ public final class VideoDetailFragment
|
||||||
valueAnimator.start();
|
valueAnimator.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
|
||||||
// Player related utils
|
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
|
||||||
|
|
||||||
private void showSystemUi() {
|
private void showSystemUi() {
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
Log.d(TAG, "showSystemUi() called");
|
Log.d(TAG, "showSystemUi() called");
|
||||||
|
@ -1974,6 +1924,10 @@ public final class VideoDetailFragment
|
||||||
android.R.attr.colorPrimary));
|
android.R.attr.colorPrimary));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
|
// Player related utils
|
||||||
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
private void hideSystemUi() {
|
private void hideSystemUi() {
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
Log.d(TAG, "hideSystemUi() called");
|
Log.d(TAG, "hideSystemUi() called");
|
||||||
|
@ -2197,10 +2151,6 @@ public final class VideoDetailFragment
|
||||||
updateOverlayData(null, null, null);
|
updateOverlayData(null, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
|
||||||
// Bottom mini player
|
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* That's for Android TV support. Move focus from main fragment to the player or back
|
* That's for Android TV support. Move focus from main fragment to the player or back
|
||||||
* based on what is currently selected
|
* based on what is currently selected
|
||||||
|
@ -2235,6 +2185,10 @@ public final class VideoDetailFragment
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
|
// Bottom mini player
|
||||||
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* When the mini player exists the view underneath it is not touchable.
|
* When the mini player exists the view underneath it is not touchable.
|
||||||
* Bottom padding should be equal to the mini player's height in this case
|
* Bottom padding should be equal to the mini player's height in this case
|
||||||
|
@ -2443,4 +2397,6 @@ public final class VideoDetailFragment
|
||||||
lastStableBottomSheetState = newState;
|
lastStableBottomSheetState = newState;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,5 @@
|
||||||
package org.schabi.newpipe.fragments.detail;
|
package org.schabi.newpipe.fragments.detail;
|
||||||
|
|
||||||
import static com.google.android.exoplayer2.PlaybackException.ERROR_CODE_BEHIND_LIVE_WINDOW;
|
|
||||||
import static com.google.android.exoplayer2.PlaybackException.ERROR_CODE_DECODING_FAILED;
|
|
||||||
import static com.google.android.exoplayer2.PlaybackException.ERROR_CODE_UNSPECIFIED;
|
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.util.Pair;
|
import android.util.Pair;
|
||||||
|
@ -13,15 +9,12 @@ import android.view.ViewGroup;
|
||||||
import android.widget.RadioButton;
|
import android.widget.RadioButton;
|
||||||
import android.widget.RadioGroup;
|
import android.widget.RadioGroup;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.appcompat.app.AlertDialog;
|
import androidx.appcompat.app.AlertDialog;
|
||||||
|
|
||||||
import com.google.android.exoplayer2.C;
|
import com.google.android.exoplayer2.C;
|
||||||
import com.google.android.exoplayer2.ExoPlaybackException;
|
import com.google.android.exoplayer2.ExoPlaybackException;
|
||||||
import com.google.android.exoplayer2.PlaybackException;
|
import com.google.android.exoplayer2.PlaybackException;
|
||||||
|
|
||||||
import org.schabi.newpipe.R;
|
import org.schabi.newpipe.R;
|
||||||
import org.schabi.newpipe.databinding.ListRadioIconItemBinding;
|
import org.schabi.newpipe.databinding.ListRadioIconItemBinding;
|
||||||
import org.schabi.newpipe.databinding.SingleChoiceDialogViewBinding;
|
import org.schabi.newpipe.databinding.SingleChoiceDialogViewBinding;
|
||||||
|
@ -32,6 +25,8 @@ import java.io.IOException;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
import static com.google.android.exoplayer2.PlaybackException.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Outsourced logic for crashing the player in the {@link VideoDetailFragment}.
|
* Outsourced logic for crashing the player in the {@link VideoDetailFragment}.
|
||||||
*/
|
*/
|
||||||
|
@ -46,25 +41,25 @@ public final class VideoDetailPlayerCrasher {
|
||||||
|
|
||||||
private static final List<Pair<String, Supplier<ExoPlaybackException>>>
|
private static final List<Pair<String, Supplier<ExoPlaybackException>>>
|
||||||
AVAILABLE_EXCEPTION_TYPES = List.of(
|
AVAILABLE_EXCEPTION_TYPES = List.of(
|
||||||
new Pair<>("Source", () -> ExoPlaybackException.createForSource(
|
new Pair<>("Source", () -> ExoPlaybackException.createForSource(
|
||||||
new IOException(DEFAULT_MSG),
|
new IOException(DEFAULT_MSG),
|
||||||
ERROR_CODE_BEHIND_LIVE_WINDOW
|
ERROR_CODE_BEHIND_LIVE_WINDOW
|
||||||
)),
|
)),
|
||||||
new Pair<>("Renderer", () -> ExoPlaybackException.createForRenderer(
|
new Pair<>("Renderer", () -> ExoPlaybackException.createForRenderer(
|
||||||
new Exception(DEFAULT_MSG),
|
new Exception(DEFAULT_MSG),
|
||||||
"Dummy renderer",
|
"Dummy renderer",
|
||||||
0,
|
0,
|
||||||
null,
|
null,
|
||||||
C.FORMAT_HANDLED,
|
C.FORMAT_HANDLED,
|
||||||
/*isRecoverable=*/false,
|
/*isRecoverable=*/false,
|
||||||
ERROR_CODE_DECODING_FAILED
|
ERROR_CODE_DECODING_FAILED
|
||||||
)),
|
)),
|
||||||
new Pair<>("Unexpected", () -> ExoPlaybackException.createForUnexpected(
|
new Pair<>("Unexpected", () -> ExoPlaybackException.createForUnexpected(
|
||||||
new RuntimeException(DEFAULT_MSG),
|
new RuntimeException(DEFAULT_MSG),
|
||||||
ERROR_CODE_UNSPECIFIED
|
ERROR_CODE_UNSPECIFIED
|
||||||
)),
|
)),
|
||||||
new Pair<>("Remote", () -> ExoPlaybackException.createForRemote(DEFAULT_MSG))
|
new Pair<>("Remote", () -> ExoPlaybackException.createForRemote(DEFAULT_MSG))
|
||||||
);
|
);
|
||||||
|
|
||||||
private VideoDetailPlayerCrasher() {
|
private VideoDetailPlayerCrasher() {
|
||||||
// No impls
|
// No impls
|
||||||
|
@ -127,6 +122,7 @@ public final class VideoDetailPlayerCrasher {
|
||||||
/**
|
/**
|
||||||
* Note that this method does not crash the underlying exoplayer directly (it's not possible).
|
* Note that this method does not crash the underlying exoplayer directly (it's not possible).
|
||||||
* It simply supplies a Exception to {@link Player#onPlayerError(PlaybackException)}.
|
* It simply supplies a Exception to {@link Player#onPlayerError(PlaybackException)}.
|
||||||
|
*
|
||||||
* @param player
|
* @param player
|
||||||
* @param exception
|
* @param exception
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -1,8 +1,5 @@
|
||||||
package org.schabi.newpipe.fragments.list;
|
package org.schabi.newpipe.fragments.list;
|
||||||
|
|
||||||
import static org.schabi.newpipe.ktx.ViewUtils.animate;
|
|
||||||
import static org.schabi.newpipe.ktx.ViewUtils.animateHideRecyclerViewAllowingScrolling;
|
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.content.res.Resources;
|
import android.content.res.Resources;
|
||||||
|
@ -11,14 +8,12 @@ import android.util.Log;
|
||||||
import android.view.Menu;
|
import android.view.Menu;
|
||||||
import android.view.MenuInflater;
|
import android.view.MenuInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.appcompat.app.ActionBar;
|
import androidx.appcompat.app.ActionBar;
|
||||||
import androidx.preference.PreferenceManager;
|
import androidx.preference.PreferenceManager;
|
||||||
import androidx.recyclerview.widget.GridLayoutManager;
|
import androidx.recyclerview.widget.GridLayoutManager;
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
import org.schabi.newpipe.R;
|
import org.schabi.newpipe.R;
|
||||||
import org.schabi.newpipe.error.ErrorUtil;
|
import org.schabi.newpipe.error.ErrorUtil;
|
||||||
import org.schabi.newpipe.extractor.InfoItem;
|
import org.schabi.newpipe.extractor.InfoItem;
|
||||||
|
@ -38,21 +33,22 @@ import java.util.List;
|
||||||
import java.util.Queue;
|
import java.util.Queue;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
import static org.schabi.newpipe.ktx.ViewUtils.animate;
|
||||||
|
import static org.schabi.newpipe.ktx.ViewUtils.animateHideRecyclerViewAllowingScrolling;
|
||||||
|
|
||||||
public abstract class BaseListFragment<I, N> extends BaseStateFragment<I>
|
public abstract class BaseListFragment<I, N> extends BaseStateFragment<I>
|
||||||
implements ListViewContract<I, N>, StateSaver.WriteRead,
|
implements ListViewContract<I, N>, StateSaver.WriteRead,
|
||||||
SharedPreferences.OnSharedPreferenceChangeListener {
|
SharedPreferences.OnSharedPreferenceChangeListener {
|
||||||
private static final int LIST_MODE_UPDATE_FLAG = 0x32;
|
private static final int LIST_MODE_UPDATE_FLAG = 0x32;
|
||||||
protected org.schabi.newpipe.util.SavedState savedState;
|
protected org.schabi.newpipe.util.SavedState savedState;
|
||||||
|
protected InfoListAdapter infoListAdapter;
|
||||||
private boolean useDefaultStateSaving = true;
|
protected RecyclerView itemsList;
|
||||||
private int updateFlags = 0;
|
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
// Views
|
// Views
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
private boolean useDefaultStateSaving = true;
|
||||||
protected InfoListAdapter infoListAdapter;
|
private int updateFlags = 0;
|
||||||
protected RecyclerView itemsList;
|
|
||||||
private int focusedPosition = -1;
|
private int focusedPosition = -1;
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -366,13 +362,6 @@ public abstract class BaseListFragment<I, N> extends BaseStateFragment<I>
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
class DefaultItemListOnScrolledDownListener extends OnScrollBelowItemsListener {
|
|
||||||
@Override
|
|
||||||
public void onScrolledDown(final RecyclerView recyclerView) {
|
|
||||||
onScrollToBottom();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void onStreamSelected(final StreamInfoItem selectedItem) {
|
private void onStreamSelected(final StreamInfoItem selectedItem) {
|
||||||
onItemSelected(selectedItem);
|
onItemSelected(selectedItem);
|
||||||
NavigationHelper.openVideoDetailFragment(requireContext(), getFM(),
|
NavigationHelper.openVideoDetailFragment(requireContext(), getFM(),
|
||||||
|
@ -394,10 +383,6 @@ public abstract class BaseListFragment<I, N> extends BaseStateFragment<I>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
|
||||||
// Menu
|
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreateOptionsMenu(@NonNull final Menu menu,
|
public void onCreateOptionsMenu(@NonNull final Menu menu,
|
||||||
@NonNull final MenuInflater inflater) {
|
@NonNull final MenuInflater inflater) {
|
||||||
|
@ -414,7 +399,7 @@ public abstract class BaseListFragment<I, N> extends BaseStateFragment<I>
|
||||||
}
|
}
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
// Load and handle
|
// Menu
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -423,20 +408,24 @@ public abstract class BaseListFragment<I, N> extends BaseStateFragment<I>
|
||||||
super.startLoading(forceLoad);
|
super.startLoading(forceLoad);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
|
// Load and handle
|
||||||
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
protected abstract void loadMoreItems();
|
protected abstract void loadMoreItems();
|
||||||
|
|
||||||
protected abstract boolean hasMoreItems();
|
protected abstract boolean hasMoreItems();
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
|
||||||
// Contract
|
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void showLoading() {
|
public void showLoading() {
|
||||||
super.showLoading();
|
super.showLoading();
|
||||||
animateHideRecyclerViewAllowingScrolling(itemsList);
|
animateHideRecyclerViewAllowingScrolling(itemsList);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
|
// Contract
|
||||||
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void hideLoading() {
|
public void hideLoading() {
|
||||||
super.hideLoading();
|
super.hideLoading();
|
||||||
|
@ -481,9 +470,17 @@ public abstract class BaseListFragment<I, N> extends BaseStateFragment<I>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns preferred item view mode.
|
* Returns preferred item view mode.
|
||||||
|
*
|
||||||
* @return ItemViewMode
|
* @return ItemViewMode
|
||||||
*/
|
*/
|
||||||
protected ItemViewMode getItemViewMode() {
|
protected ItemViewMode getItemViewMode() {
|
||||||
return ThemeHelper.getItemViewMode(requireContext());
|
return ThemeHelper.getItemViewMode(requireContext());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class DefaultItemListOnScrolledDownListener extends OnScrollBelowItemsListener {
|
||||||
|
@Override
|
||||||
|
public void onScrolledDown(final RecyclerView recyclerView) {
|
||||||
|
onScrollToBottom();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,9 +4,12 @@ import android.os.Bundle;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
|
import icepick.State;
|
||||||
|
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
|
||||||
|
import io.reactivex.rxjava3.core.Single;
|
||||||
|
import io.reactivex.rxjava3.disposables.Disposable;
|
||||||
|
import io.reactivex.rxjava3.schedulers.Schedulers;
|
||||||
import org.schabi.newpipe.error.ErrorInfo;
|
import org.schabi.newpipe.error.ErrorInfo;
|
||||||
import org.schabi.newpipe.error.UserAction;
|
import org.schabi.newpipe.error.UserAction;
|
||||||
import org.schabi.newpipe.extractor.InfoItem;
|
import org.schabi.newpipe.extractor.InfoItem;
|
||||||
|
@ -22,22 +25,15 @@ import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Queue;
|
import java.util.Queue;
|
||||||
|
|
||||||
import icepick.State;
|
|
||||||
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
|
|
||||||
import io.reactivex.rxjava3.core.Single;
|
|
||||||
import io.reactivex.rxjava3.disposables.Disposable;
|
|
||||||
import io.reactivex.rxjava3.schedulers.Schedulers;
|
|
||||||
|
|
||||||
public abstract class BaseListInfoFragment<I extends InfoItem, L extends ListInfo<I>>
|
public abstract class BaseListInfoFragment<I extends InfoItem, L extends ListInfo<I>>
|
||||||
extends BaseListFragment<L, ListExtractor.InfoItemsPage<I>> {
|
extends BaseListFragment<L, ListExtractor.InfoItemsPage<I>> {
|
||||||
|
private final UserAction errorUserAction;
|
||||||
@State
|
@State
|
||||||
protected int serviceId = Constants.NO_SERVICE_ID;
|
protected int serviceId = Constants.NO_SERVICE_ID;
|
||||||
@State
|
@State
|
||||||
protected String name;
|
protected String name;
|
||||||
@State
|
@State
|
||||||
protected String url;
|
protected String url;
|
||||||
|
|
||||||
private final UserAction errorUserAction;
|
|
||||||
protected L currentInfo;
|
protected L currentInfo;
|
||||||
protected Page currentNextPage;
|
protected Page currentNextPage;
|
||||||
protected Disposable currentWorker;
|
protected Disposable currentWorker;
|
||||||
|
|
|
@ -1,31 +1,28 @@
|
||||||
package org.schabi.newpipe.fragments.list.channel;
|
package org.schabi.newpipe.fragments.list.channel;
|
||||||
|
|
||||||
import static org.schabi.newpipe.ktx.TextViewUtils.animateTextColor;
|
|
||||||
import static org.schabi.newpipe.ktx.ViewUtils.animate;
|
|
||||||
import static org.schabi.newpipe.ktx.ViewUtils.animateBackgroundColor;
|
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.graphics.Color;
|
import android.graphics.Color;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.util.TypedValue;
|
import android.util.TypedValue;
|
||||||
import android.view.LayoutInflater;
|
import android.view.*;
|
||||||
import android.view.Menu;
|
|
||||||
import android.view.MenuInflater;
|
|
||||||
import android.view.MenuItem;
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.ViewGroup;
|
|
||||||
import android.widget.Button;
|
import android.widget.Button;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.appcompat.app.ActionBar;
|
import androidx.appcompat.app.ActionBar;
|
||||||
import androidx.core.content.ContextCompat;
|
import androidx.core.content.ContextCompat;
|
||||||
|
|
||||||
import com.google.android.material.snackbar.Snackbar;
|
import com.google.android.material.snackbar.Snackbar;
|
||||||
import com.jakewharton.rxbinding4.view.RxView;
|
import com.jakewharton.rxbinding4.view.RxView;
|
||||||
|
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
|
||||||
|
import io.reactivex.rxjava3.core.Observable;
|
||||||
|
import io.reactivex.rxjava3.core.Single;
|
||||||
|
import io.reactivex.rxjava3.disposables.CompositeDisposable;
|
||||||
|
import io.reactivex.rxjava3.disposables.Disposable;
|
||||||
|
import io.reactivex.rxjava3.functions.Action;
|
||||||
|
import io.reactivex.rxjava3.functions.Consumer;
|
||||||
|
import io.reactivex.rxjava3.functions.Function;
|
||||||
|
import io.reactivex.rxjava3.schedulers.Schedulers;
|
||||||
import org.schabi.newpipe.R;
|
import org.schabi.newpipe.R;
|
||||||
import org.schabi.newpipe.database.subscription.NotificationMode;
|
import org.schabi.newpipe.database.subscription.NotificationMode;
|
||||||
import org.schabi.newpipe.database.subscription.SubscriptionEntity;
|
import org.schabi.newpipe.database.subscription.SubscriptionEntity;
|
||||||
|
@ -41,16 +38,12 @@ import org.schabi.newpipe.extractor.exceptions.ContentNotSupportedException;
|
||||||
import org.schabi.newpipe.extractor.stream.StreamInfoItem;
|
import org.schabi.newpipe.extractor.stream.StreamInfoItem;
|
||||||
import org.schabi.newpipe.fragments.list.BaseListInfoFragment;
|
import org.schabi.newpipe.fragments.list.BaseListInfoFragment;
|
||||||
import org.schabi.newpipe.ktx.AnimationType;
|
import org.schabi.newpipe.ktx.AnimationType;
|
||||||
import org.schabi.newpipe.local.subscription.SubscriptionManager;
|
|
||||||
import org.schabi.newpipe.local.feed.notifications.NotificationHelper;
|
import org.schabi.newpipe.local.feed.notifications.NotificationHelper;
|
||||||
|
import org.schabi.newpipe.local.subscription.SubscriptionManager;
|
||||||
import org.schabi.newpipe.player.PlayerType;
|
import org.schabi.newpipe.player.PlayerType;
|
||||||
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.util.ExtractorHelper;
|
import org.schabi.newpipe.util.*;
|
||||||
import org.schabi.newpipe.util.Localization;
|
|
||||||
import org.schabi.newpipe.util.NavigationHelper;
|
|
||||||
import org.schabi.newpipe.util.PicassoHelper;
|
|
||||||
import org.schabi.newpipe.util.ThemeHelper;
|
|
||||||
import org.schabi.newpipe.util.external_communication.ShareUtils;
|
import org.schabi.newpipe.util.external_communication.ShareUtils;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -58,15 +51,9 @@ import java.util.concurrent.TimeUnit;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
|
import static org.schabi.newpipe.ktx.TextViewUtils.animateTextColor;
|
||||||
import io.reactivex.rxjava3.core.Observable;
|
import static org.schabi.newpipe.ktx.ViewUtils.animate;
|
||||||
import io.reactivex.rxjava3.core.Single;
|
import static org.schabi.newpipe.ktx.ViewUtils.animateBackgroundColor;
|
||||||
import io.reactivex.rxjava3.disposables.CompositeDisposable;
|
|
||||||
import io.reactivex.rxjava3.disposables.Disposable;
|
|
||||||
import io.reactivex.rxjava3.functions.Action;
|
|
||||||
import io.reactivex.rxjava3.functions.Consumer;
|
|
||||||
import io.reactivex.rxjava3.functions.Function;
|
|
||||||
import io.reactivex.rxjava3.schedulers.Schedulers;
|
|
||||||
|
|
||||||
public class ChannelFragment extends BaseListInfoFragment<StreamInfoItem, ChannelInfo>
|
public class ChannelFragment extends BaseListInfoFragment<StreamInfoItem, ChannelInfo>
|
||||||
implements View.OnClickListener {
|
implements View.OnClickListener {
|
||||||
|
@ -92,6 +79,10 @@ public class ChannelFragment extends BaseListInfoFragment<StreamInfoItem, Channe
|
||||||
private MenuItem menuRssButton;
|
private MenuItem menuRssButton;
|
||||||
private MenuItem menuNotifyButton;
|
private MenuItem menuNotifyButton;
|
||||||
|
|
||||||
|
public ChannelFragment() {
|
||||||
|
super(UserAction.REQUESTED_CHANNEL);
|
||||||
|
}
|
||||||
|
|
||||||
public static ChannelFragment getInstance(final int serviceId, final String url,
|
public static ChannelFragment getInstance(final int serviceId, final String url,
|
||||||
final String name) {
|
final String name) {
|
||||||
final ChannelFragment instance = new ChannelFragment();
|
final ChannelFragment instance = new ChannelFragment();
|
||||||
|
@ -99,10 +90,6 @@ public class ChannelFragment extends BaseListInfoFragment<StreamInfoItem, Channe
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ChannelFragment() {
|
|
||||||
super(UserAction.REQUESTED_CHANNEL);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onResume() {
|
public void onResume() {
|
||||||
super.onResume();
|
super.onResume();
|
||||||
|
|
|
@ -1,16 +1,12 @@
|
||||||
package org.schabi.newpipe.fragments.list.comments;
|
package org.schabi.newpipe.fragments.list.comments;
|
||||||
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.view.LayoutInflater;
|
import android.view.*;
|
||||||
import android.view.Menu;
|
|
||||||
import android.view.MenuInflater;
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.ViewGroup;
|
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
import io.reactivex.rxjava3.core.Single;
|
||||||
|
import io.reactivex.rxjava3.disposables.CompositeDisposable;
|
||||||
import org.schabi.newpipe.R;
|
import org.schabi.newpipe.R;
|
||||||
import org.schabi.newpipe.error.UserAction;
|
import org.schabi.newpipe.error.UserAction;
|
||||||
import org.schabi.newpipe.extractor.ListExtractor;
|
import org.schabi.newpipe.extractor.ListExtractor;
|
||||||
|
@ -21,14 +17,15 @@ import org.schabi.newpipe.info_list.ItemViewMode;
|
||||||
import org.schabi.newpipe.ktx.ViewUtils;
|
import org.schabi.newpipe.ktx.ViewUtils;
|
||||||
import org.schabi.newpipe.util.ExtractorHelper;
|
import org.schabi.newpipe.util.ExtractorHelper;
|
||||||
|
|
||||||
import io.reactivex.rxjava3.core.Single;
|
|
||||||
import io.reactivex.rxjava3.disposables.CompositeDisposable;
|
|
||||||
|
|
||||||
public class CommentsFragment extends BaseListInfoFragment<CommentsInfoItem, CommentsInfo> {
|
public class CommentsFragment extends BaseListInfoFragment<CommentsInfoItem, CommentsInfo> {
|
||||||
private final CompositeDisposable disposables = new CompositeDisposable();
|
private final CompositeDisposable disposables = new CompositeDisposable();
|
||||||
|
|
||||||
private TextView emptyStateDesc;
|
private TextView emptyStateDesc;
|
||||||
|
|
||||||
|
public CommentsFragment() {
|
||||||
|
super(UserAction.REQUESTED_COMMENTS);
|
||||||
|
}
|
||||||
|
|
||||||
public static CommentsFragment getInstance(final int serviceId, final String url,
|
public static CommentsFragment getInstance(final int serviceId, final String url,
|
||||||
final String name) {
|
final String name) {
|
||||||
final CommentsFragment instance = new CommentsFragment();
|
final CommentsFragment instance = new CommentsFragment();
|
||||||
|
@ -36,10 +33,6 @@ public class CommentsFragment extends BaseListInfoFragment<CommentsInfoItem, Com
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
public CommentsFragment() {
|
|
||||||
super(UserAction.REQUESTED_COMMENTS);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void initViews(final View rootView, final Bundle savedInstanceState) {
|
protected void initViews(final View rootView, final Bundle savedInstanceState) {
|
||||||
super.initViews(rootView, savedInstanceState);
|
super.initViews(rootView, savedInstanceState);
|
||||||
|
@ -100,11 +93,13 @@ public class CommentsFragment extends BaseListInfoFragment<CommentsInfoItem, Com
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setTitle(final String title) { }
|
public void setTitle(final String title) {
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreateOptionsMenu(@NonNull final Menu menu,
|
public void onCreateOptionsMenu(@NonNull final Menu menu,
|
||||||
@NonNull final MenuInflater inflater) { }
|
@NonNull final MenuInflater inflater) {
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected ItemViewMode getItemViewMode() {
|
protected ItemViewMode getItemViewMode() {
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package org.schabi.newpipe.fragments.list.kiosk;
|
package org.schabi.newpipe.fragments.list.kiosk;
|
||||||
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
|
||||||
import org.schabi.newpipe.error.ErrorInfo;
|
import org.schabi.newpipe.error.ErrorInfo;
|
||||||
import org.schabi.newpipe.error.UserAction;
|
import org.schabi.newpipe.error.UserAction;
|
||||||
import org.schabi.newpipe.extractor.NewPipe;
|
import org.schabi.newpipe.extractor.NewPipe;
|
||||||
|
|
|
@ -1,16 +1,12 @@
|
||||||
package org.schabi.newpipe.fragments.list.kiosk;
|
package org.schabi.newpipe.fragments.list.kiosk;
|
||||||
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.view.LayoutInflater;
|
import android.view.*;
|
||||||
import android.view.Menu;
|
|
||||||
import android.view.MenuInflater;
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.ViewGroup;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.appcompat.app.ActionBar;
|
import androidx.appcompat.app.ActionBar;
|
||||||
|
import icepick.State;
|
||||||
|
import io.reactivex.rxjava3.core.Single;
|
||||||
import org.schabi.newpipe.R;
|
import org.schabi.newpipe.R;
|
||||||
import org.schabi.newpipe.error.ErrorInfo;
|
import org.schabi.newpipe.error.ErrorInfo;
|
||||||
import org.schabi.newpipe.error.UserAction;
|
import org.schabi.newpipe.error.UserAction;
|
||||||
|
@ -27,9 +23,6 @@ import org.schabi.newpipe.util.ExtractorHelper;
|
||||||
import org.schabi.newpipe.util.KioskTranslator;
|
import org.schabi.newpipe.util.KioskTranslator;
|
||||||
import org.schabi.newpipe.util.Localization;
|
import org.schabi.newpipe.util.Localization;
|
||||||
|
|
||||||
import icepick.State;
|
|
||||||
import io.reactivex.rxjava3.core.Single;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by Christian Schabesberger on 23.09.17.
|
* Created by Christian Schabesberger on 23.09.17.
|
||||||
* <p>
|
* <p>
|
||||||
|
@ -65,6 +58,10 @@ public class KioskFragment extends BaseListInfoFragment<StreamInfoItem, KioskInf
|
||||||
// Views
|
// Views
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
|
public KioskFragment() {
|
||||||
|
super(UserAction.REQUESTED_KIOSK);
|
||||||
|
}
|
||||||
|
|
||||||
public static KioskFragment getInstance(final int serviceId) throws ExtractionException {
|
public static KioskFragment getInstance(final int serviceId) throws ExtractionException {
|
||||||
return getInstance(serviceId, NewPipe.getService(serviceId)
|
return getInstance(serviceId, NewPipe.getService(serviceId)
|
||||||
.getKioskList().getDefaultKioskId());
|
.getKioskList().getDefaultKioskId());
|
||||||
|
@ -82,10 +79,6 @@ public class KioskFragment extends BaseListInfoFragment<StreamInfoItem, KioskInf
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
public KioskFragment() {
|
|
||||||
super(UserAction.REQUESTED_KIOSK);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
// LifeCycle
|
// LifeCycle
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
|
@ -1,26 +1,20 @@
|
||||||
package org.schabi.newpipe.fragments.list.playlist;
|
package org.schabi.newpipe.fragments.list.playlist;
|
||||||
|
|
||||||
import static org.schabi.newpipe.ktx.ViewUtils.animate;
|
|
||||||
import static org.schabi.newpipe.ktx.ViewUtils.animateHideRecyclerViewAllowingScrolling;
|
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.LayoutInflater;
|
import android.view.*;
|
||||||
import android.view.Menu;
|
|
||||||
import android.view.MenuInflater;
|
|
||||||
import android.view.MenuItem;
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.ViewGroup;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.appcompat.content.res.AppCompatResources;
|
import androidx.appcompat.content.res.AppCompatResources;
|
||||||
|
|
||||||
import com.google.android.material.shape.CornerFamily;
|
import com.google.android.material.shape.CornerFamily;
|
||||||
import com.google.android.material.shape.ShapeAppearanceModel;
|
import com.google.android.material.shape.ShapeAppearanceModel;
|
||||||
|
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
|
||||||
|
import io.reactivex.rxjava3.core.Flowable;
|
||||||
|
import io.reactivex.rxjava3.core.Single;
|
||||||
|
import io.reactivex.rxjava3.disposables.CompositeDisposable;
|
||||||
|
import io.reactivex.rxjava3.disposables.Disposable;
|
||||||
import org.reactivestreams.Subscriber;
|
import org.reactivestreams.Subscriber;
|
||||||
import org.reactivestreams.Subscription;
|
import org.reactivestreams.Subscription;
|
||||||
import org.schabi.newpipe.NewPipeDatabase;
|
import org.schabi.newpipe.NewPipeDatabase;
|
||||||
|
@ -58,11 +52,8 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
|
import static org.schabi.newpipe.ktx.ViewUtils.animate;
|
||||||
import io.reactivex.rxjava3.core.Flowable;
|
import static org.schabi.newpipe.ktx.ViewUtils.animateHideRecyclerViewAllowingScrolling;
|
||||||
import io.reactivex.rxjava3.core.Single;
|
|
||||||
import io.reactivex.rxjava3.disposables.CompositeDisposable;
|
|
||||||
import io.reactivex.rxjava3.disposables.Disposable;
|
|
||||||
|
|
||||||
public class PlaylistFragment extends BaseListInfoFragment<StreamInfoItem, PlaylistInfo> {
|
public class PlaylistFragment extends BaseListInfoFragment<StreamInfoItem, PlaylistInfo> {
|
||||||
|
|
||||||
|
@ -84,6 +75,10 @@ public class PlaylistFragment extends BaseListInfoFragment<StreamInfoItem, Playl
|
||||||
|
|
||||||
private MenuItem playlistBookmarkButton;
|
private MenuItem playlistBookmarkButton;
|
||||||
|
|
||||||
|
public PlaylistFragment() {
|
||||||
|
super(UserAction.REQUESTED_PLAYLIST);
|
||||||
|
}
|
||||||
|
|
||||||
public static PlaylistFragment getInstance(final int serviceId, final String url,
|
public static PlaylistFragment getInstance(final int serviceId, final String url,
|
||||||
final String name) {
|
final String name) {
|
||||||
final PlaylistFragment instance = new PlaylistFragment();
|
final PlaylistFragment instance = new PlaylistFragment();
|
||||||
|
@ -91,10 +86,6 @@ public class PlaylistFragment extends BaseListInfoFragment<StreamInfoItem, Playl
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
public PlaylistFragment() {
|
|
||||||
super(UserAction.REQUESTED_PLAYLIST);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
// LifeCycle
|
// LifeCycle
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
@ -311,7 +302,7 @@ public class PlaylistFragment extends BaseListInfoFragment<StreamInfoItem, Playl
|
||||||
.getColorStateList(requireContext(), R.color.transparent_background_color));
|
.getColorStateList(requireContext(), R.color.transparent_background_color));
|
||||||
headerBinding.uploaderAvatarView.setImageDrawable(
|
headerBinding.uploaderAvatarView.setImageDrawable(
|
||||||
AppCompatResources.getDrawable(requireContext(),
|
AppCompatResources.getDrawable(requireContext(),
|
||||||
R.drawable.ic_radio)
|
R.drawable.ic_radio)
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
PicassoHelper.loadAvatar(avatarUrl).tag(PICASSO_PLAYLIST_TAG)
|
PicassoHelper.loadAvatar(avatarUrl).tag(PICASSO_PLAYLIST_TAG)
|
||||||
|
@ -420,7 +411,8 @@ public class PlaylistFragment extends BaseListInfoFragment<StreamInfoItem, Playl
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onComplete() { }
|
public void onComplete() {
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,5 @@
|
||||||
package org.schabi.newpipe.fragments.list.search;
|
package org.schabi.newpipe.fragments.list.search;
|
||||||
|
|
||||||
import static androidx.recyclerview.widget.ItemTouchHelper.Callback.makeMovementFlags;
|
|
||||||
import static org.schabi.newpipe.ktx.ViewUtils.animate;
|
|
||||||
import static org.schabi.newpipe.util.ExtractorHelper.showMetaInfoInTextView;
|
|
||||||
import static java.util.Arrays.asList;
|
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
@ -16,18 +11,11 @@ import android.text.TextUtils;
|
||||||
import android.text.TextWatcher;
|
import android.text.TextWatcher;
|
||||||
import android.text.style.CharacterStyle;
|
import android.text.style.CharacterStyle;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.KeyEvent;
|
import android.view.*;
|
||||||
import android.view.LayoutInflater;
|
|
||||||
import android.view.Menu;
|
|
||||||
import android.view.MenuInflater;
|
|
||||||
import android.view.MenuItem;
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.ViewGroup;
|
|
||||||
import android.view.animation.DecelerateInterpolator;
|
import android.view.animation.DecelerateInterpolator;
|
||||||
import android.view.inputmethod.EditorInfo;
|
import android.view.inputmethod.EditorInfo;
|
||||||
import android.widget.EditText;
|
import android.widget.EditText;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.appcompat.app.ActionBar;
|
import androidx.appcompat.app.ActionBar;
|
||||||
|
@ -38,19 +26,21 @@ import androidx.core.text.HtmlCompat;
|
||||||
import androidx.preference.PreferenceManager;
|
import androidx.preference.PreferenceManager;
|
||||||
import androidx.recyclerview.widget.ItemTouchHelper;
|
import androidx.recyclerview.widget.ItemTouchHelper;
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
import icepick.State;
|
||||||
|
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
|
||||||
|
import io.reactivex.rxjava3.core.Observable;
|
||||||
|
import io.reactivex.rxjava3.core.Single;
|
||||||
|
import io.reactivex.rxjava3.disposables.CompositeDisposable;
|
||||||
|
import io.reactivex.rxjava3.disposables.Disposable;
|
||||||
|
import io.reactivex.rxjava3.schedulers.Schedulers;
|
||||||
|
import io.reactivex.rxjava3.subjects.PublishSubject;
|
||||||
import org.schabi.newpipe.R;
|
import org.schabi.newpipe.R;
|
||||||
import org.schabi.newpipe.databinding.FragmentSearchBinding;
|
import org.schabi.newpipe.databinding.FragmentSearchBinding;
|
||||||
import org.schabi.newpipe.error.ErrorInfo;
|
import org.schabi.newpipe.error.ErrorInfo;
|
||||||
import org.schabi.newpipe.error.ErrorUtil;
|
import org.schabi.newpipe.error.ErrorUtil;
|
||||||
import org.schabi.newpipe.error.ReCaptchaActivity;
|
import org.schabi.newpipe.error.ReCaptchaActivity;
|
||||||
import org.schabi.newpipe.error.UserAction;
|
import org.schabi.newpipe.error.UserAction;
|
||||||
import org.schabi.newpipe.extractor.InfoItem;
|
import org.schabi.newpipe.extractor.*;
|
||||||
import org.schabi.newpipe.extractor.ListExtractor;
|
|
||||||
import org.schabi.newpipe.extractor.MetaInfo;
|
|
||||||
import org.schabi.newpipe.extractor.NewPipe;
|
|
||||||
import org.schabi.newpipe.extractor.Page;
|
|
||||||
import org.schabi.newpipe.extractor.StreamingService;
|
|
||||||
import org.schabi.newpipe.extractor.search.SearchExtractor;
|
import org.schabi.newpipe.extractor.search.SearchExtractor;
|
||||||
import org.schabi.newpipe.extractor.search.SearchInfo;
|
import org.schabi.newpipe.extractor.search.SearchInfo;
|
||||||
import org.schabi.newpipe.extractor.services.peertube.linkHandler.PeertubeSearchQueryHandlerFactory;
|
import org.schabi.newpipe.extractor.services.peertube.linkHandler.PeertubeSearchQueryHandlerFactory;
|
||||||
|
@ -61,29 +51,16 @@ import org.schabi.newpipe.ktx.AnimationType;
|
||||||
import org.schabi.newpipe.ktx.ExceptionUtils;
|
import org.schabi.newpipe.ktx.ExceptionUtils;
|
||||||
import org.schabi.newpipe.local.history.HistoryRecordManager;
|
import org.schabi.newpipe.local.history.HistoryRecordManager;
|
||||||
import org.schabi.newpipe.settings.NewPipeSettings;
|
import org.schabi.newpipe.settings.NewPipeSettings;
|
||||||
import org.schabi.newpipe.util.Constants;
|
import org.schabi.newpipe.util.*;
|
||||||
import org.schabi.newpipe.util.DeviceUtils;
|
|
||||||
import org.schabi.newpipe.util.ExtractorHelper;
|
|
||||||
import org.schabi.newpipe.util.KeyboardUtil;
|
|
||||||
import org.schabi.newpipe.util.NavigationHelper;
|
|
||||||
import org.schabi.newpipe.util.ServiceHelper;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Queue;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import icepick.State;
|
import static androidx.recyclerview.widget.ItemTouchHelper.Callback.makeMovementFlags;
|
||||||
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
|
import static java.util.Arrays.asList;
|
||||||
import io.reactivex.rxjava3.core.Observable;
|
import static org.schabi.newpipe.ktx.ViewUtils.animate;
|
||||||
import io.reactivex.rxjava3.core.Single;
|
import static org.schabi.newpipe.util.ExtractorHelper.showMetaInfoInTextView;
|
||||||
import io.reactivex.rxjava3.disposables.CompositeDisposable;
|
|
||||||
import io.reactivex.rxjava3.disposables.Disposable;
|
|
||||||
import io.reactivex.rxjava3.schedulers.Schedulers;
|
|
||||||
import io.reactivex.rxjava3.subjects.PublishSubject;
|
|
||||||
|
|
||||||
public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.InfoItemsPage<?>>
|
public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.InfoItemsPage<?>>
|
||||||
implements BackPressable {
|
implements BackPressable {
|
||||||
|
@ -103,53 +80,40 @@ public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.I
|
||||||
*/
|
*/
|
||||||
private static final int SUGGESTIONS_DEBOUNCE = 120; //ms
|
private static final int SUGGESTIONS_DEBOUNCE = 120; //ms
|
||||||
private final PublishSubject<String> suggestionPublisher = PublishSubject.create();
|
private final PublishSubject<String> suggestionPublisher = PublishSubject.create();
|
||||||
|
private final SparseArrayCompat<String> menuItemToFilterName = new SparseArrayCompat<>();
|
||||||
@State
|
private final CompositeDisposable disposables = new CompositeDisposable();
|
||||||
int filterItemCheckedId = -1;
|
|
||||||
|
|
||||||
@State
|
@State
|
||||||
protected int serviceId = Constants.NO_SERVICE_ID;
|
protected int serviceId = Constants.NO_SERVICE_ID;
|
||||||
|
@State
|
||||||
|
int filterItemCheckedId = -1;
|
||||||
// these three represents the current search query
|
// these three represents the current search query
|
||||||
@State
|
@State
|
||||||
String searchString;
|
String searchString;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* No content filter should add like contentFilter = all
|
* No content filter should add like contentFilter = all
|
||||||
* be aware of this when implementing an extractor.
|
* be aware of this when implementing an extractor.
|
||||||
*/
|
*/
|
||||||
@State
|
@State
|
||||||
String[] contentFilter = new String[0];
|
String[] contentFilter = new String[0];
|
||||||
|
|
||||||
@State
|
@State
|
||||||
String sortFilter;
|
String sortFilter;
|
||||||
|
|
||||||
// these represents the last search
|
// these represents the last search
|
||||||
@State
|
@State
|
||||||
String lastSearchedString;
|
String lastSearchedString;
|
||||||
|
|
||||||
@State
|
@State
|
||||||
String searchSuggestion;
|
String searchSuggestion;
|
||||||
|
|
||||||
@State
|
@State
|
||||||
boolean isCorrectedSearch;
|
boolean isCorrectedSearch;
|
||||||
|
|
||||||
@State
|
@State
|
||||||
MetaInfo[] metaInfo;
|
MetaInfo[] metaInfo;
|
||||||
|
|
||||||
@State
|
@State
|
||||||
boolean wasSearchFocused = false;
|
boolean wasSearchFocused = false;
|
||||||
|
|
||||||
private final SparseArrayCompat<String> menuItemToFilterName = new SparseArrayCompat<>();
|
|
||||||
private StreamingService service;
|
private StreamingService service;
|
||||||
private Page nextPage;
|
private Page nextPage;
|
||||||
private boolean showLocalSuggestions = true;
|
private boolean showLocalSuggestions = true;
|
||||||
private boolean showRemoteSuggestions = true;
|
private boolean showRemoteSuggestions = true;
|
||||||
|
|
||||||
private Disposable searchDisposable;
|
private Disposable searchDisposable;
|
||||||
private Disposable suggestionDisposable;
|
private Disposable suggestionDisposable;
|
||||||
private final CompositeDisposable disposables = new CompositeDisposable();
|
|
||||||
|
|
||||||
private SuggestionListAdapter suggestionListAdapter;
|
private SuggestionListAdapter suggestionListAdapter;
|
||||||
private HistoryRecordManager historyRecordManager;
|
private HistoryRecordManager historyRecordManager;
|
||||||
|
|
||||||
|
@ -717,9 +681,9 @@ public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.I
|
||||||
.getRelatedSearches(query, similarQueryLimit, 25)
|
.getRelatedSearches(query, similarQueryLimit, 25)
|
||||||
.toObservable()
|
.toObservable()
|
||||||
.map(searchHistoryEntries ->
|
.map(searchHistoryEntries ->
|
||||||
searchHistoryEntries.stream()
|
searchHistoryEntries.stream()
|
||||||
.map(entry -> new SuggestionItem(true, entry))
|
.map(entry -> new SuggestionItem(true, entry))
|
||||||
.collect(Collectors.toList()));
|
.collect(Collectors.toList()));
|
||||||
}
|
}
|
||||||
|
|
||||||
private Observable<List<SuggestionItem>> getRemoteSuggestionsObservable(final String query) {
|
private Observable<List<SuggestionItem>> getRemoteSuggestionsObservable(final String query) {
|
||||||
|
@ -754,14 +718,14 @@ public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.I
|
||||||
|
|
||||||
if (showLocalSuggestions && shallShowRemoteSuggestionsNow) {
|
if (showLocalSuggestions && shallShowRemoteSuggestionsNow) {
|
||||||
return Observable.zip(
|
return Observable.zip(
|
||||||
getLocalSuggestionsObservable(query, 3),
|
getLocalSuggestionsObservable(query, 3),
|
||||||
getRemoteSuggestionsObservable(query),
|
getRemoteSuggestionsObservable(query),
|
||||||
(local, remote) -> {
|
(local, remote) -> {
|
||||||
remote.removeIf(remoteItem -> local.stream().anyMatch(
|
remote.removeIf(remoteItem -> local.stream().anyMatch(
|
||||||
localItem -> localItem.equals(remoteItem)));
|
localItem -> localItem.equals(remoteItem)));
|
||||||
local.addAll(remote);
|
local.addAll(remote);
|
||||||
return local;
|
return local;
|
||||||
})
|
})
|
||||||
.materialize();
|
.materialize();
|
||||||
} else if (showLocalSuggestions) {
|
} else if (showLocalSuggestions) {
|
||||||
return getLocalSuggestionsObservable(query, 25)
|
return getLocalSuggestionsObservable(query, 25)
|
||||||
|
@ -786,12 +750,12 @@ public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.I
|
||||||
} else if (listNotification.isOnError()
|
} else if (listNotification.isOnError()
|
||||||
&& listNotification.getError() != null
|
&& listNotification.getError() != null
|
||||||
&& !ExceptionUtils.isInterruptedCaused(
|
&& !ExceptionUtils.isInterruptedCaused(
|
||||||
listNotification.getError())) {
|
listNotification.getError())) {
|
||||||
showSnackBarError(new ErrorInfo(listNotification.getError(),
|
showSnackBarError(new ErrorInfo(listNotification.getError(),
|
||||||
UserAction.GET_SUGGESTIONS, searchString, serviceId));
|
UserAction.GET_SUGGESTIONS, searchString, serviceId));
|
||||||
}
|
}
|
||||||
}, throwable -> showSnackBarError(new ErrorInfo(
|
}, throwable -> showSnackBarError(new ErrorInfo(
|
||||||
throwable, UserAction.GET_SUGGESTIONS, searchString, serviceId)));
|
throwable, UserAction.GET_SUGGESTIONS, searchString, serviceId)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -839,7 +803,8 @@ public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.I
|
||||||
disposables.add(historyRecordManager.onSearched(serviceId, theSearchString)
|
disposables.add(historyRecordManager.onSearched(serviceId, theSearchString)
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
.subscribe(
|
.subscribe(
|
||||||
ignored -> { },
|
ignored -> {
|
||||||
|
},
|
||||||
throwable -> showSnackBarError(new ErrorInfo(throwable, UserAction.SEARCHED,
|
throwable -> showSnackBarError(new ErrorInfo(throwable, UserAction.SEARCHED,
|
||||||
theSearchString, serviceId))
|
theSearchString, serviceId))
|
||||||
));
|
));
|
||||||
|
@ -855,9 +820,9 @@ public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.I
|
||||||
searchDisposable.dispose();
|
searchDisposable.dispose();
|
||||||
}
|
}
|
||||||
searchDisposable = ExtractorHelper.searchFor(serviceId,
|
searchDisposable = ExtractorHelper.searchFor(serviceId,
|
||||||
searchString,
|
searchString,
|
||||||
Arrays.asList(contentFilter),
|
Arrays.asList(contentFilter),
|
||||||
sortFilter)
|
sortFilter)
|
||||||
.subscribeOn(Schedulers.io())
|
.subscribeOn(Schedulers.io())
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
.doOnEvent((searchResult, throwable) -> isLoading.set(false))
|
.doOnEvent((searchResult, throwable) -> isLoading.set(false))
|
||||||
|
@ -876,11 +841,11 @@ public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.I
|
||||||
searchDisposable.dispose();
|
searchDisposable.dispose();
|
||||||
}
|
}
|
||||||
searchDisposable = ExtractorHelper.getMoreSearchItems(
|
searchDisposable = ExtractorHelper.getMoreSearchItems(
|
||||||
serviceId,
|
serviceId,
|
||||||
searchString,
|
searchString,
|
||||||
asList(contentFilter),
|
asList(contentFilter),
|
||||||
sortFilter,
|
sortFilter,
|
||||||
nextPage)
|
nextPage)
|
||||||
.subscribeOn(Schedulers.io())
|
.subscribeOn(Schedulers.io())
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
.doOnEvent((nextItemsResult, throwable) -> isLoading.set(false))
|
.doOnEvent((nextItemsResult, throwable) -> isLoading.set(false))
|
||||||
|
|
|
@ -3,8 +3,8 @@ package org.schabi.newpipe.fragments.list.search;
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
public class SuggestionItem {
|
public class SuggestionItem {
|
||||||
final boolean fromHistory;
|
|
||||||
public final String query;
|
public final String query;
|
||||||
|
final boolean fromHistory;
|
||||||
|
|
||||||
public SuggestionItem(final boolean fromHistory, final String query) {
|
public SuggestionItem(final boolean fromHistory, final String query) {
|
||||||
this.fromHistory = fromHistory;
|
this.fromHistory = fromHistory;
|
||||||
|
|
|
@ -2,12 +2,10 @@ package org.schabi.newpipe.fragments.list.search;
|
||||||
|
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.recyclerview.widget.DiffUtil;
|
import androidx.recyclerview.widget.DiffUtil;
|
||||||
import androidx.recyclerview.widget.ListAdapter;
|
import androidx.recyclerview.widget.ListAdapter;
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
import org.schabi.newpipe.R;
|
import org.schabi.newpipe.R;
|
||||||
import org.schabi.newpipe.databinding.ItemSearchSuggestionBinding;
|
import org.schabi.newpipe.databinding.ItemSearchSuggestionBinding;
|
||||||
|
|
||||||
|
|
|
@ -2,16 +2,11 @@ package org.schabi.newpipe.fragments.list.videos;
|
||||||
|
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.view.LayoutInflater;
|
import android.view.*;
|
||||||
import android.view.Menu;
|
|
||||||
import android.view.MenuInflater;
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.ViewGroup;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.preference.PreferenceManager;
|
import androidx.preference.PreferenceManager;
|
||||||
|
import io.reactivex.rxjava3.core.Single;
|
||||||
import org.schabi.newpipe.R;
|
import org.schabi.newpipe.R;
|
||||||
import org.schabi.newpipe.databinding.RelatedItemsHeaderBinding;
|
import org.schabi.newpipe.databinding.RelatedItemsHeaderBinding;
|
||||||
import org.schabi.newpipe.error.UserAction;
|
import org.schabi.newpipe.error.UserAction;
|
||||||
|
@ -26,8 +21,6 @@ import org.schabi.newpipe.util.RelatedItemInfo;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
import io.reactivex.rxjava3.core.Single;
|
|
||||||
|
|
||||||
public class RelatedItemsFragment extends BaseListInfoFragment<InfoItem, RelatedItemInfo>
|
public class RelatedItemsFragment extends BaseListInfoFragment<InfoItem, RelatedItemInfo>
|
||||||
implements SharedPreferences.OnSharedPreferenceChangeListener {
|
implements SharedPreferences.OnSharedPreferenceChangeListener {
|
||||||
private static final String INFO_KEY = "related_info_key";
|
private static final String INFO_KEY = "related_info_key";
|
||||||
|
@ -40,16 +33,16 @@ public class RelatedItemsFragment extends BaseListInfoFragment<InfoItem, Related
|
||||||
|
|
||||||
private RelatedItemsHeaderBinding headerBinding;
|
private RelatedItemsHeaderBinding headerBinding;
|
||||||
|
|
||||||
|
public RelatedItemsFragment() {
|
||||||
|
super(UserAction.REQUESTED_STREAM);
|
||||||
|
}
|
||||||
|
|
||||||
public static RelatedItemsFragment getInstance(final StreamInfo info) {
|
public static RelatedItemsFragment getInstance(final StreamInfo info) {
|
||||||
final RelatedItemsFragment instance = new RelatedItemsFragment();
|
final RelatedItemsFragment instance = new RelatedItemsFragment();
|
||||||
instance.setInitialData(info);
|
instance.setInitialData(info);
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
public RelatedItemsFragment() {
|
|
||||||
super(UserAction.REQUESTED_STREAM);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
// LifeCycle
|
// LifeCycle
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
|
@ -3,23 +3,13 @@ package org.schabi.newpipe.info_list;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
import org.schabi.newpipe.extractor.InfoItem;
|
import org.schabi.newpipe.extractor.InfoItem;
|
||||||
import org.schabi.newpipe.extractor.channel.ChannelInfoItem;
|
import org.schabi.newpipe.extractor.channel.ChannelInfoItem;
|
||||||
import org.schabi.newpipe.extractor.comments.CommentsInfoItem;
|
import org.schabi.newpipe.extractor.comments.CommentsInfoItem;
|
||||||
import org.schabi.newpipe.extractor.playlist.PlaylistInfoItem;
|
import org.schabi.newpipe.extractor.playlist.PlaylistInfoItem;
|
||||||
import org.schabi.newpipe.extractor.stream.StreamInfoItem;
|
import org.schabi.newpipe.extractor.stream.StreamInfoItem;
|
||||||
import org.schabi.newpipe.info_list.holder.ChannelInfoItemHolder;
|
import org.schabi.newpipe.info_list.holder.*;
|
||||||
import org.schabi.newpipe.info_list.holder.ChannelMiniInfoItemHolder;
|
|
||||||
import org.schabi.newpipe.info_list.holder.CommentsInfoItemHolder;
|
|
||||||
import org.schabi.newpipe.info_list.holder.CommentsMiniInfoItemHolder;
|
|
||||||
import org.schabi.newpipe.info_list.holder.InfoItemHolder;
|
|
||||||
import org.schabi.newpipe.info_list.holder.PlaylistInfoItemHolder;
|
|
||||||
import org.schabi.newpipe.info_list.holder.PlaylistMiniInfoItemHolder;
|
|
||||||
import org.schabi.newpipe.info_list.holder.StreamInfoItemHolder;
|
|
||||||
import org.schabi.newpipe.info_list.holder.StreamMiniInfoItemHolder;
|
|
||||||
import org.schabi.newpipe.local.history.HistoryRecordManager;
|
import org.schabi.newpipe.local.history.HistoryRecordManager;
|
||||||
import org.schabi.newpipe.util.OnClickGesture;
|
import org.schabi.newpipe.util.OnClickGesture;
|
||||||
|
|
||||||
|
|
|
@ -5,32 +5,17 @@ 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;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.recyclerview.widget.GridLayoutManager;
|
import androidx.recyclerview.widget.GridLayoutManager;
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
import org.schabi.newpipe.databinding.PignateFooterBinding;
|
import org.schabi.newpipe.databinding.PignateFooterBinding;
|
||||||
import org.schabi.newpipe.extractor.InfoItem;
|
import org.schabi.newpipe.extractor.InfoItem;
|
||||||
import org.schabi.newpipe.extractor.channel.ChannelInfoItem;
|
import org.schabi.newpipe.extractor.channel.ChannelInfoItem;
|
||||||
import org.schabi.newpipe.extractor.comments.CommentsInfoItem;
|
import org.schabi.newpipe.extractor.comments.CommentsInfoItem;
|
||||||
import org.schabi.newpipe.extractor.playlist.PlaylistInfoItem;
|
import org.schabi.newpipe.extractor.playlist.PlaylistInfoItem;
|
||||||
import org.schabi.newpipe.extractor.stream.StreamInfoItem;
|
import org.schabi.newpipe.extractor.stream.StreamInfoItem;
|
||||||
import org.schabi.newpipe.info_list.holder.ChannelGridInfoItemHolder;
|
import org.schabi.newpipe.info_list.holder.*;
|
||||||
import org.schabi.newpipe.info_list.holder.ChannelInfoItemHolder;
|
|
||||||
import org.schabi.newpipe.info_list.holder.ChannelMiniInfoItemHolder;
|
|
||||||
import org.schabi.newpipe.info_list.holder.CommentsInfoItemHolder;
|
|
||||||
import org.schabi.newpipe.info_list.holder.CommentsMiniInfoItemHolder;
|
|
||||||
import org.schabi.newpipe.info_list.holder.InfoItemHolder;
|
|
||||||
import org.schabi.newpipe.info_list.holder.PlaylistCardInfoItemHolder;
|
|
||||||
import org.schabi.newpipe.info_list.holder.PlaylistGridInfoItemHolder;
|
|
||||||
import org.schabi.newpipe.info_list.holder.PlaylistInfoItemHolder;
|
|
||||||
import org.schabi.newpipe.info_list.holder.PlaylistMiniInfoItemHolder;
|
|
||||||
import org.schabi.newpipe.info_list.holder.StreamCardInfoItemHolder;
|
|
||||||
import org.schabi.newpipe.info_list.holder.StreamGridInfoItemHolder;
|
|
||||||
import org.schabi.newpipe.info_list.holder.StreamInfoItemHolder;
|
|
||||||
import org.schabi.newpipe.info_list.holder.StreamMiniInfoItemHolder;
|
|
||||||
import org.schabi.newpipe.local.history.HistoryRecordManager;
|
import org.schabi.newpipe.local.history.HistoryRecordManager;
|
||||||
import org.schabi.newpipe.util.FallbackViewHolder;
|
import org.schabi.newpipe.util.FallbackViewHolder;
|
||||||
import org.schabi.newpipe.util.OnClickGesture;
|
import org.schabi.newpipe.util.OnClickGesture;
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
package org.schabi.newpipe.info_list.dialog;
|
package org.schabi.newpipe.info_list.dialog;
|
||||||
|
|
||||||
import static org.schabi.newpipe.MainActivity.DEBUG;
|
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.DialogInterface;
|
import android.content.DialogInterface;
|
||||||
|
@ -9,12 +7,10 @@ import android.os.Build;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.appcompat.app.AlertDialog;
|
import androidx.appcompat.app.AlertDialog;
|
||||||
import androidx.fragment.app.Fragment;
|
import androidx.fragment.app.Fragment;
|
||||||
import androidx.preference.PreferenceManager;
|
import androidx.preference.PreferenceManager;
|
||||||
|
|
||||||
import org.schabi.newpipe.App;
|
import org.schabi.newpipe.App;
|
||||||
import org.schabi.newpipe.R;
|
import org.schabi.newpipe.R;
|
||||||
import org.schabi.newpipe.error.ErrorInfo;
|
import org.schabi.newpipe.error.ErrorInfo;
|
||||||
|
@ -31,6 +27,8 @@ import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
import static org.schabi.newpipe.MainActivity.DEBUG;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Dialog for a {@link StreamInfoItem}.
|
* Dialog for a {@link StreamInfoItem}.
|
||||||
* The dialog's content are actions that can be performed on the {@link StreamInfoItem}.
|
* The dialog's content are actions that can be performed on the {@link StreamInfoItem}.
|
||||||
|
@ -73,7 +71,7 @@ public final class InfoItemDialog {
|
||||||
|
|
||||||
// Call an entry's action / onClick method when the entry is selected.
|
// Call an entry's action / onClick method when the entry is selected.
|
||||||
final DialogInterface.OnClickListener action = (d, index) ->
|
final DialogInterface.OnClickListener action = (d, index) ->
|
||||||
entries.get(index).action.onClick(fragment, info);
|
entries.get(index).action.onClick(fragment, info);
|
||||||
|
|
||||||
dialog = new AlertDialog.Builder(activity)
|
dialog = new AlertDialog.Builder(activity)
|
||||||
.setCustomTitle(bannerView)
|
.setCustomTitle(bannerView)
|
||||||
|
@ -95,11 +93,16 @@ public final class InfoItemDialog {
|
||||||
* {@link #setAction(StreamDialogDefaultEntry, StreamDialogEntry.StreamDialogEntryAction)}.
|
* {@link #setAction(StreamDialogDefaultEntry, StreamDialogEntry.StreamDialogEntryAction)}.
|
||||||
*/
|
*/
|
||||||
public static class Builder {
|
public static class Builder {
|
||||||
@NonNull private final Activity activity;
|
@NonNull
|
||||||
@NonNull private final Context context;
|
private final Activity activity;
|
||||||
@NonNull private final StreamInfoItem infoItem;
|
@NonNull
|
||||||
@NonNull private final Fragment fragment;
|
private final Context context;
|
||||||
@NonNull private final List<StreamDialogEntry> entries = new ArrayList<>();
|
@NonNull
|
||||||
|
private final StreamInfoItem infoItem;
|
||||||
|
@NonNull
|
||||||
|
private final Fragment fragment;
|
||||||
|
@NonNull
|
||||||
|
private final List<StreamDialogEntry> entries = new ArrayList<>();
|
||||||
private final boolean addDefaultEntriesAutomatically;
|
private final boolean addDefaultEntriesAutomatically;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -132,9 +135,9 @@ public final class InfoItemDialog {
|
||||||
* @param context
|
* @param context
|
||||||
* @param fragment
|
* @param fragment
|
||||||
* @param infoItem the item for this dialog; all entries and their actions work with
|
* @param infoItem the item for this dialog; all entries and their actions work with
|
||||||
* this {@link StreamInfoItem}
|
* this {@link StreamInfoItem}
|
||||||
* @throws IllegalArgumentException if <code>activity, context</code>
|
* @throws IllegalArgumentException if <code>activity, context</code>
|
||||||
* or resources is <code>null</code>
|
* or resources is <code>null</code>
|
||||||
*/
|
*/
|
||||||
public Builder(final Activity activity,
|
public Builder(final Activity activity,
|
||||||
final Context context,
|
final Context context,
|
||||||
|
@ -173,15 +176,14 @@ public final class InfoItemDialog {
|
||||||
* @param context
|
* @param context
|
||||||
* @param fragment
|
* @param fragment
|
||||||
* @param infoItem
|
* @param infoItem
|
||||||
* @param addDefaultEntriesAutomatically
|
* @param addDefaultEntriesAutomatically whether default entries added with {@link #addDefaultBeginningEntries()}
|
||||||
* whether default entries added with {@link #addDefaultBeginningEntries()}
|
* and {@link #addDefaultEndEntries()} are added automatically when generating
|
||||||
* and {@link #addDefaultEndEntries()} are added automatically when generating
|
* the {@link InfoItemDialog}.
|
||||||
* the {@link InfoItemDialog}.
|
* <br/>
|
||||||
* <br/>
|
* Entries added with {@link #addEntry(StreamDialogDefaultEntry)} and
|
||||||
* Entries added with {@link #addEntry(StreamDialogDefaultEntry)} and
|
* {@link #addAllEntries(StreamDialogDefaultEntry...)} are added in between.
|
||||||
* {@link #addAllEntries(StreamDialogDefaultEntry...)} are added in between.
|
|
||||||
* @throws IllegalArgumentException if <code>activity, context</code>
|
* @throws IllegalArgumentException if <code>activity, context</code>
|
||||||
* or resources is <code>null</code>
|
* or resources is <code>null</code>
|
||||||
*/
|
*/
|
||||||
public Builder(final Activity activity,
|
public Builder(final Activity activity,
|
||||||
final Context context,
|
final Context context,
|
||||||
|
@ -205,8 +207,18 @@ public final class InfoItemDialog {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void reportErrorDuringInitialization(final Throwable throwable,
|
||||||
|
final InfoItem item) {
|
||||||
|
ErrorUtil.showSnackbar(App.getApp().getBaseContext(), new ErrorInfo(
|
||||||
|
throwable,
|
||||||
|
UserAction.OPEN_INFO_ITEM_DIALOG,
|
||||||
|
"none",
|
||||||
|
item.getServiceId()));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds a new entry and appends it to the current entry list.
|
* Adds a new entry and appends it to the current entry list.
|
||||||
|
*
|
||||||
* @param entry the entry to add
|
* @param entry the entry to add
|
||||||
* @return the current {@link Builder} instance
|
* @return the current {@link Builder} instance
|
||||||
*/
|
*/
|
||||||
|
@ -217,6 +229,7 @@ public final class InfoItemDialog {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds new entries. These are appended to the current entry list.
|
* Adds new entries. These are appended to the current entry list.
|
||||||
|
*
|
||||||
* @param newEntries the entries to add
|
* @param newEntries the entries to add
|
||||||
* @return the current {@link Builder} instance
|
* @return the current {@link Builder} instance
|
||||||
*/
|
*/
|
||||||
|
@ -230,12 +243,13 @@ public final class InfoItemDialog {
|
||||||
* <p><strong>Warning:</strong> Only use this method when the entry has been already added.
|
* <p><strong>Warning:</strong> Only use this method when the entry has been already added.
|
||||||
* Changing the action of an entry which has not been added to the Builder yet
|
* Changing the action of an entry which has not been added to the Builder yet
|
||||||
* does not have an effect.</p>
|
* does not have an effect.</p>
|
||||||
* @param entry the entry to change
|
*
|
||||||
|
* @param entry the entry to change
|
||||||
* @param action the action to perform when the entry is selected
|
* @param action the action to perform when the entry is selected
|
||||||
* @return the current {@link Builder} instance
|
* @return the current {@link Builder} instance
|
||||||
*/
|
*/
|
||||||
public Builder setAction(@NonNull final StreamDialogDefaultEntry entry,
|
public Builder setAction(@NonNull final StreamDialogDefaultEntry entry,
|
||||||
@NonNull final StreamDialogEntry.StreamDialogEntryAction action) {
|
@NonNull final StreamDialogEntry.StreamDialogEntryAction action) {
|
||||||
for (int i = 0; i < entries.size(); i++) {
|
for (int i = 0; i < entries.size(); i++) {
|
||||||
if (entries.get(i).resource == entry.resource) {
|
if (entries.get(i).resource == entry.resource) {
|
||||||
entries.set(i, new StreamDialogEntry(entry.resource, action));
|
entries.set(i, new StreamDialogEntry(entry.resource, action));
|
||||||
|
@ -249,6 +263,7 @@ public final class InfoItemDialog {
|
||||||
* Adds {@link StreamDialogDefaultEntry#ENQUEUE} if the player is open and
|
* Adds {@link StreamDialogDefaultEntry#ENQUEUE} if the player is open and
|
||||||
* {@link StreamDialogDefaultEntry#ENQUEUE_NEXT} if there are multiple streams
|
* {@link StreamDialogDefaultEntry#ENQUEUE_NEXT} if there are multiple streams
|
||||||
* in the play queue.
|
* in the play queue.
|
||||||
|
*
|
||||||
* @return the current {@link Builder} instance
|
* @return the current {@link Builder} instance
|
||||||
*/
|
*/
|
||||||
public Builder addEnqueueEntriesIfNeeded() {
|
public Builder addEnqueueEntriesIfNeeded() {
|
||||||
|
@ -267,6 +282,7 @@ public final class InfoItemDialog {
|
||||||
* Adds the {@link StreamDialogDefaultEntry#START_HERE_ON_BACKGROUND}.
|
* Adds the {@link StreamDialogDefaultEntry#START_HERE_ON_BACKGROUND}.
|
||||||
* If the {@link #infoItem} is not a pure audio (live) stream,
|
* If the {@link #infoItem} is not a pure audio (live) stream,
|
||||||
* {@link StreamDialogDefaultEntry#START_HERE_ON_POPUP} is added, too.
|
* {@link StreamDialogDefaultEntry#START_HERE_ON_POPUP} is added, too.
|
||||||
|
*
|
||||||
* @return the current {@link Builder} instance
|
* @return the current {@link Builder} instance
|
||||||
*/
|
*/
|
||||||
public Builder addStartHereEntries() {
|
public Builder addStartHereEntries() {
|
||||||
|
@ -280,6 +296,7 @@ public final class InfoItemDialog {
|
||||||
/**
|
/**
|
||||||
* Adds {@link StreamDialogDefaultEntry#MARK_AS_WATCHED} if the watch history is enabled
|
* Adds {@link StreamDialogDefaultEntry#MARK_AS_WATCHED} if the watch history is enabled
|
||||||
* and the stream is not a livestream.
|
* and the stream is not a livestream.
|
||||||
|
*
|
||||||
* @return the current {@link Builder} instance
|
* @return the current {@link Builder} instance
|
||||||
*/
|
*/
|
||||||
public Builder addMarkAsWatchedEntryIfNeeded() {
|
public Builder addMarkAsWatchedEntryIfNeeded() {
|
||||||
|
@ -294,6 +311,7 @@ public final class InfoItemDialog {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds the {@link StreamDialogDefaultEntry#PLAY_WITH_KODI} entry if it is needed.
|
* Adds the {@link StreamDialogDefaultEntry#PLAY_WITH_KODI} entry if it is needed.
|
||||||
|
*
|
||||||
* @return the current {@link Builder} instance
|
* @return the current {@link Builder} instance
|
||||||
*/
|
*/
|
||||||
public Builder addPlayWithKodiEntryIfNeeded() {
|
public Builder addPlayWithKodiEntryIfNeeded() {
|
||||||
|
@ -308,6 +326,7 @@ public final class InfoItemDialog {
|
||||||
* <br/>
|
* <br/>
|
||||||
* This method adds the "enqueue" (see {@link #addEnqueueEntriesIfNeeded()})
|
* This method adds the "enqueue" (see {@link #addEnqueueEntriesIfNeeded()})
|
||||||
* and "start here" (see {@link #addStartHereEntries()} entries.
|
* and "start here" (see {@link #addStartHereEntries()} entries.
|
||||||
|
*
|
||||||
* @return the current {@link Builder} instance
|
* @return the current {@link Builder} instance
|
||||||
*/
|
*/
|
||||||
public Builder addDefaultBeginningEntries() {
|
public Builder addDefaultBeginningEntries() {
|
||||||
|
@ -318,6 +337,7 @@ public final class InfoItemDialog {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add the entries which are usually at the bottom of the action list.
|
* Add the entries which are usually at the bottom of the action list.
|
||||||
|
*
|
||||||
* @return the current {@link Builder} instance
|
* @return the current {@link Builder} instance
|
||||||
*/
|
*/
|
||||||
public Builder addDefaultEndEntries() {
|
public Builder addDefaultEndEntries() {
|
||||||
|
@ -335,6 +355,7 @@ public final class InfoItemDialog {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates the {@link InfoItemDialog}.
|
* Creates the {@link InfoItemDialog}.
|
||||||
|
*
|
||||||
* @return a new instance of {@link InfoItemDialog}
|
* @return a new instance of {@link InfoItemDialog}
|
||||||
*/
|
*/
|
||||||
public InfoItemDialog create() {
|
public InfoItemDialog create() {
|
||||||
|
@ -343,14 +364,5 @@ public final class InfoItemDialog {
|
||||||
}
|
}
|
||||||
return new InfoItemDialog(this.activity, this.fragment, this.infoItem, this.entries);
|
return new InfoItemDialog(this.activity, this.fragment, this.infoItem, this.entries);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void reportErrorDuringInitialization(final Throwable throwable,
|
|
||||||
final InfoItem item) {
|
|
||||||
ErrorUtil.showSnackbar(App.getApp().getBaseContext(), new ErrorInfo(
|
|
||||||
throwable,
|
|
||||||
UserAction.OPEN_INFO_ITEM_DIALOG,
|
|
||||||
"none",
|
|
||||||
item.getServiceId()));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,15 +1,9 @@
|
||||||
package org.schabi.newpipe.info_list.dialog;
|
package org.schabi.newpipe.info_list.dialog;
|
||||||
|
|
||||||
import static org.schabi.newpipe.util.NavigationHelper.openChannelFragment;
|
|
||||||
import static org.schabi.newpipe.util.SparseItemUtil.fetchItemInfoIfSparse;
|
|
||||||
import static org.schabi.newpipe.util.SparseItemUtil.fetchStreamInfoAndSaveToDatabase;
|
|
||||||
import static org.schabi.newpipe.util.SparseItemUtil.fetchUploaderUrlIfSparse;
|
|
||||||
|
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.StringRes;
|
import androidx.annotation.StringRes;
|
||||||
|
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
|
||||||
import org.schabi.newpipe.R;
|
import org.schabi.newpipe.R;
|
||||||
import org.schabi.newpipe.database.stream.model.StreamEntity;
|
import org.schabi.newpipe.database.stream.model.StreamEntity;
|
||||||
import org.schabi.newpipe.download.DownloadDialog;
|
import org.schabi.newpipe.download.DownloadDialog;
|
||||||
|
@ -22,22 +16,23 @@ import org.schabi.newpipe.util.external_communication.ShareUtils;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
|
import static org.schabi.newpipe.util.NavigationHelper.openChannelFragment;
|
||||||
|
import static org.schabi.newpipe.util.SparseItemUtil.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>
|
* <p>
|
||||||
* This enum provides entries that are accepted
|
* This enum provides entries that are accepted
|
||||||
* by the {@link InfoItemDialog.Builder}.
|
* by the {@link InfoItemDialog.Builder}.
|
||||||
* </p>
|
* </p>
|
||||||
* <p>
|
* <p>
|
||||||
* These entries contain a String {@link #resource} which is displayed in the dialog and
|
* These entries contain a String {@link #resource} which is displayed in the dialog and
|
||||||
* a default {@link #action} that is executed
|
* a default {@link #action} that is executed
|
||||||
* when the entry is selected (via <code>onClick()</code>).
|
* when the entry is selected (via <code>onClick()</code>).
|
||||||
* <br/>
|
* <br/>
|
||||||
* They action can be overridden by using the Builder's
|
* They action can be overridden by using the Builder's
|
||||||
* {@link InfoItemDialog.Builder#setAction(
|
* {@link InfoItemDialog.Builder#setAction(
|
||||||
* StreamDialogDefaultEntry, StreamDialogEntry.StreamDialogEntryAction)}
|
*StreamDialogDefaultEntry, StreamDialogEntry.StreamDialogEntryAction)}
|
||||||
* method.
|
* method.
|
||||||
* </p>
|
* </p>
|
||||||
*/
|
*/
|
||||||
public enum StreamDialogDefaultEntry {
|
public enum StreamDialogDefaultEntry {
|
||||||
|
@ -51,7 +46,7 @@ public enum StreamDialogDefaultEntry {
|
||||||
*/
|
*/
|
||||||
ENQUEUE(R.string.enqueue_stream, (fragment, item) ->
|
ENQUEUE(R.string.enqueue_stream, (fragment, item) ->
|
||||||
fetchItemInfoIfSparse(fragment.requireContext(), item, singlePlayQueue ->
|
fetchItemInfoIfSparse(fragment.requireContext(), item, singlePlayQueue ->
|
||||||
NavigationHelper.enqueueOnPlayer(fragment.getContext(), singlePlayQueue))
|
NavigationHelper.enqueueOnPlayer(fragment.getContext(), singlePlayQueue))
|
||||||
),
|
),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -60,17 +55,17 @@ public enum StreamDialogDefaultEntry {
|
||||||
*/
|
*/
|
||||||
ENQUEUE_NEXT(R.string.enqueue_next_stream, (fragment, item) ->
|
ENQUEUE_NEXT(R.string.enqueue_next_stream, (fragment, item) ->
|
||||||
fetchItemInfoIfSparse(fragment.requireContext(), item, singlePlayQueue ->
|
fetchItemInfoIfSparse(fragment.requireContext(), item, singlePlayQueue ->
|
||||||
NavigationHelper.enqueueNextOnPlayer(fragment.getContext(), singlePlayQueue))
|
NavigationHelper.enqueueNextOnPlayer(fragment.getContext(), singlePlayQueue))
|
||||||
),
|
),
|
||||||
|
|
||||||
START_HERE_ON_BACKGROUND(R.string.start_here_on_background, (fragment, item) ->
|
START_HERE_ON_BACKGROUND(R.string.start_here_on_background, (fragment, item) ->
|
||||||
fetchItemInfoIfSparse(fragment.requireContext(), item, singlePlayQueue ->
|
fetchItemInfoIfSparse(fragment.requireContext(), item, singlePlayQueue ->
|
||||||
NavigationHelper.playOnBackgroundPlayer(
|
NavigationHelper.playOnBackgroundPlayer(
|
||||||
fragment.getContext(), singlePlayQueue, true))),
|
fragment.getContext(), singlePlayQueue, true))),
|
||||||
|
|
||||||
START_HERE_ON_POPUP(R.string.start_here_on_popup, (fragment, item) ->
|
START_HERE_ON_POPUP(R.string.start_here_on_popup, (fragment, item) ->
|
||||||
fetchItemInfoIfSparse(fragment.requireContext(), item, singlePlayQueue ->
|
fetchItemInfoIfSparse(fragment.requireContext(), item, singlePlayQueue ->
|
||||||
NavigationHelper.playOnPopupPlayer(fragment.getContext(), singlePlayQueue, true))),
|
NavigationHelper.playOnPopupPlayer(fragment.getContext(), singlePlayQueue, true))),
|
||||||
|
|
||||||
SET_AS_PLAYLIST_THUMBNAIL(R.string.set_as_playlist_thumbnail, (fragment, item) -> {
|
SET_AS_PLAYLIST_THUMBNAIL(R.string.set_as_playlist_thumbnail, (fragment, item) -> {
|
||||||
throw new UnsupportedOperationException("This needs to be implemented manually "
|
throw new UnsupportedOperationException("This needs to be implemented manually "
|
||||||
|
@ -87,16 +82,16 @@ public enum StreamDialogDefaultEntry {
|
||||||
* or create a new playlist if there are no local playlists.
|
* or create a new playlist if there are no local playlists.
|
||||||
*/
|
*/
|
||||||
APPEND_PLAYLIST(R.string.add_to_playlist, (fragment, item) ->
|
APPEND_PLAYLIST(R.string.add_to_playlist, (fragment, item) ->
|
||||||
PlaylistDialog.createCorrespondingDialog(
|
PlaylistDialog.createCorrespondingDialog(
|
||||||
fragment.getContext(),
|
fragment.getContext(),
|
||||||
List.of(new StreamEntity(item)),
|
List.of(new StreamEntity(item)),
|
||||||
dialog -> dialog.show(
|
dialog -> dialog.show(
|
||||||
fragment.getParentFragmentManager(),
|
fragment.getParentFragmentManager(),
|
||||||
"StreamDialogEntry@"
|
"StreamDialogEntry@"
|
||||||
+ (dialog instanceof PlaylistAppendDialog ? "append" : "create")
|
+ (dialog instanceof PlaylistAppendDialog ? "append" : "create")
|
||||||
+ "_playlist"
|
+ "_playlist"
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
|
|
||||||
PLAY_WITH_KODI(R.string.play_with_kodi_title, (fragment, item) -> {
|
PLAY_WITH_KODI(R.string.play_with_kodi_title, (fragment, item) -> {
|
||||||
|
@ -133,11 +128,11 @@ public enum StreamDialogDefaultEntry {
|
||||||
|
|
||||||
|
|
||||||
MARK_AS_WATCHED(R.string.mark_as_watched, (fragment, item) ->
|
MARK_AS_WATCHED(R.string.mark_as_watched, (fragment, item) ->
|
||||||
new HistoryRecordManager(fragment.getContext())
|
new HistoryRecordManager(fragment.getContext())
|
||||||
.markAsWatched(item)
|
.markAsWatched(item)
|
||||||
.onErrorComplete()
|
.onErrorComplete()
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
.subscribe()
|
.subscribe()
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,9 @@
|
||||||
package org.schabi.newpipe.info_list.dialog;
|
package org.schabi.newpipe.info_list.dialog;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.StringRes;
|
import androidx.annotation.StringRes;
|
||||||
import androidx.fragment.app.Fragment;
|
import androidx.fragment.app.Fragment;
|
||||||
|
|
||||||
import org.schabi.newpipe.extractor.stream.StreamInfoItem;
|
import org.schabi.newpipe.extractor.stream.StreamInfoItem;
|
||||||
|
|
||||||
public class StreamDialogEntry {
|
public class StreamDialogEntry {
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package org.schabi.newpipe.info_list.holder;
|
package org.schabi.newpipe.info_list.holder;
|
||||||
|
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
|
||||||
import org.schabi.newpipe.R;
|
import org.schabi.newpipe.R;
|
||||||
import org.schabi.newpipe.info_list.InfoItemBuilder;
|
import org.schabi.newpipe.info_list.InfoItemBuilder;
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package org.schabi.newpipe.info_list.holder;
|
package org.schabi.newpipe.info_list.holder;
|
||||||
|
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
|
||||||
import org.schabi.newpipe.R;
|
import org.schabi.newpipe.R;
|
||||||
import org.schabi.newpipe.info_list.InfoItemBuilder;
|
import org.schabi.newpipe.info_list.InfoItemBuilder;
|
||||||
|
|
||||||
|
|
|
@ -4,17 +4,15 @@ import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
import org.schabi.newpipe.R;
|
import org.schabi.newpipe.R;
|
||||||
import org.schabi.newpipe.extractor.InfoItem;
|
import org.schabi.newpipe.extractor.InfoItem;
|
||||||
import org.schabi.newpipe.extractor.channel.ChannelInfoItem;
|
import org.schabi.newpipe.extractor.channel.ChannelInfoItem;
|
||||||
import org.schabi.newpipe.extractor.utils.Utils;
|
import org.schabi.newpipe.extractor.utils.Utils;
|
||||||
import org.schabi.newpipe.info_list.InfoItemBuilder;
|
import org.schabi.newpipe.info_list.InfoItemBuilder;
|
||||||
import org.schabi.newpipe.local.history.HistoryRecordManager;
|
import org.schabi.newpipe.local.history.HistoryRecordManager;
|
||||||
import org.schabi.newpipe.util.PicassoHelper;
|
|
||||||
import org.schabi.newpipe.util.Localization;
|
import org.schabi.newpipe.util.Localization;
|
||||||
|
import org.schabi.newpipe.util.PicassoHelper;
|
||||||
|
|
||||||
public class ChannelMiniInfoItemHolder extends InfoItemHolder {
|
public class ChannelMiniInfoItemHolder extends InfoItemHolder {
|
||||||
private final ImageView itemThumbnailView;
|
private final ImageView itemThumbnailView;
|
||||||
|
@ -40,10 +38,9 @@ public class ChannelMiniInfoItemHolder extends InfoItemHolder {
|
||||||
@Override
|
@Override
|
||||||
public void updateFromItem(final InfoItem infoItem,
|
public void updateFromItem(final InfoItem infoItem,
|
||||||
final HistoryRecordManager historyRecordManager) {
|
final HistoryRecordManager historyRecordManager) {
|
||||||
if (!(infoItem instanceof ChannelInfoItem)) {
|
if (!(infoItem instanceof final ChannelInfoItem item)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
final ChannelInfoItem item = (ChannelInfoItem) infoItem;
|
|
||||||
|
|
||||||
itemTitleView.setText(item.getName());
|
itemTitleView.setText(item.getName());
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,6 @@ import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.widget.ImageView;
|
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.extractor.InfoItem;
|
||||||
import org.schabi.newpipe.extractor.comments.CommentsInfoItem;
|
import org.schabi.newpipe.extractor.comments.CommentsInfoItem;
|
||||||
|
@ -49,10 +48,9 @@ public class CommentsInfoItemHolder extends CommentsMiniInfoItemHolder {
|
||||||
final HistoryRecordManager historyRecordManager) {
|
final HistoryRecordManager historyRecordManager) {
|
||||||
super.updateFromItem(infoItem, historyRecordManager);
|
super.updateFromItem(infoItem, historyRecordManager);
|
||||||
|
|
||||||
if (!(infoItem instanceof CommentsInfoItem)) {
|
if (!(infoItem instanceof final CommentsInfoItem item)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
final CommentsInfoItem item = (CommentsInfoItem) infoItem;
|
|
||||||
|
|
||||||
itemTitleView.setText(item.getUploaderName());
|
itemTitleView.setText(item.getUploaderName());
|
||||||
|
|
||||||
|
|
|
@ -11,11 +11,10 @@ import android.view.ViewGroup;
|
||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
import android.widget.RelativeLayout;
|
import android.widget.RelativeLayout;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.appcompat.app.AppCompatActivity;
|
import androidx.appcompat.app.AppCompatActivity;
|
||||||
import androidx.core.text.HtmlCompat;
|
import androidx.core.text.HtmlCompat;
|
||||||
|
import io.reactivex.rxjava3.disposables.CompositeDisposable;
|
||||||
import org.schabi.newpipe.R;
|
import org.schabi.newpipe.R;
|
||||||
import org.schabi.newpipe.error.ErrorUtil;
|
import org.schabi.newpipe.error.ErrorUtil;
|
||||||
import org.schabi.newpipe.extractor.InfoItem;
|
import org.schabi.newpipe.extractor.InfoItem;
|
||||||
|
@ -37,8 +36,6 @@ import org.schabi.newpipe.util.text.TextLinkifier;
|
||||||
|
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
import io.reactivex.rxjava3.disposables.CompositeDisposable;
|
|
||||||
|
|
||||||
public class CommentsMiniInfoItemHolder extends InfoItemHolder {
|
public class CommentsMiniInfoItemHolder extends InfoItemHolder {
|
||||||
private static final String TAG = "CommentsMiniIIHolder";
|
private static final String TAG = "CommentsMiniIIHolder";
|
||||||
private static final String ELLIPSIS = "…";
|
private static final String ELLIPSIS = "…";
|
||||||
|
@ -91,10 +88,9 @@ public class CommentsMiniInfoItemHolder extends InfoItemHolder {
|
||||||
@Override
|
@Override
|
||||||
public void updateFromItem(final InfoItem infoItem,
|
public void updateFromItem(final InfoItem infoItem,
|
||||||
final HistoryRecordManager historyRecordManager) {
|
final HistoryRecordManager historyRecordManager) {
|
||||||
if (!(infoItem instanceof CommentsInfoItem)) {
|
if (!(infoItem instanceof final CommentsInfoItem item)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
final CommentsInfoItem item = (CommentsInfoItem) infoItem;
|
|
||||||
|
|
||||||
PicassoHelper.loadAvatar(item.getUploaderAvatarUrl()).into(itemThumbnailView);
|
PicassoHelper.loadAvatar(item.getUploaderAvatarUrl()).into(itemThumbnailView);
|
||||||
if (PicassoHelper.getShouldLoadImages()) {
|
if (PicassoHelper.getShouldLoadImages()) {
|
||||||
|
|
|
@ -2,9 +2,7 @@ package org.schabi.newpipe.info_list.holder;
|
||||||
|
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
import org.schabi.newpipe.extractor.InfoItem;
|
import org.schabi.newpipe.extractor.InfoItem;
|
||||||
import org.schabi.newpipe.info_list.InfoItemBuilder;
|
import org.schabi.newpipe.info_list.InfoItemBuilder;
|
||||||
import org.schabi.newpipe.local.history.HistoryRecordManager;
|
import org.schabi.newpipe.local.history.HistoryRecordManager;
|
||||||
|
@ -42,5 +40,6 @@ public abstract class InfoItemHolder extends RecyclerView.ViewHolder {
|
||||||
HistoryRecordManager historyRecordManager);
|
HistoryRecordManager historyRecordManager);
|
||||||
|
|
||||||
public void updateState(final InfoItem infoItem,
|
public void updateState(final InfoItem infoItem,
|
||||||
final HistoryRecordManager historyRecordManager) { }
|
final HistoryRecordManager historyRecordManager) {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package org.schabi.newpipe.info_list.holder;
|
package org.schabi.newpipe.info_list.holder;
|
||||||
|
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
|
||||||
import org.schabi.newpipe.R;
|
import org.schabi.newpipe.R;
|
||||||
import org.schabi.newpipe.info_list.InfoItemBuilder;
|
import org.schabi.newpipe.info_list.InfoItemBuilder;
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package org.schabi.newpipe.info_list.holder;
|
package org.schabi.newpipe.info_list.holder;
|
||||||
|
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
|
||||||
import org.schabi.newpipe.R;
|
import org.schabi.newpipe.R;
|
||||||
import org.schabi.newpipe.info_list.InfoItemBuilder;
|
import org.schabi.newpipe.info_list.InfoItemBuilder;
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package org.schabi.newpipe.info_list.holder;
|
package org.schabi.newpipe.info_list.holder;
|
||||||
|
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
|
||||||
import org.schabi.newpipe.R;
|
import org.schabi.newpipe.R;
|
||||||
import org.schabi.newpipe.info_list.InfoItemBuilder;
|
import org.schabi.newpipe.info_list.InfoItemBuilder;
|
||||||
|
|
||||||
|
|
|
@ -3,20 +3,19 @@ package org.schabi.newpipe.info_list.holder;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.widget.ImageView;
|
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.extractor.InfoItem;
|
||||||
import org.schabi.newpipe.extractor.playlist.PlaylistInfoItem;
|
import org.schabi.newpipe.extractor.playlist.PlaylistInfoItem;
|
||||||
import org.schabi.newpipe.info_list.InfoItemBuilder;
|
import org.schabi.newpipe.info_list.InfoItemBuilder;
|
||||||
import org.schabi.newpipe.local.history.HistoryRecordManager;
|
import org.schabi.newpipe.local.history.HistoryRecordManager;
|
||||||
import org.schabi.newpipe.util.PicassoHelper;
|
|
||||||
import org.schabi.newpipe.util.Localization;
|
import org.schabi.newpipe.util.Localization;
|
||||||
|
import org.schabi.newpipe.util.PicassoHelper;
|
||||||
|
|
||||||
public class PlaylistMiniInfoItemHolder extends InfoItemHolder {
|
public class PlaylistMiniInfoItemHolder extends InfoItemHolder {
|
||||||
public final ImageView itemThumbnailView;
|
public final ImageView itemThumbnailView;
|
||||||
private final TextView itemStreamCountView;
|
|
||||||
public final TextView itemTitleView;
|
public final TextView itemTitleView;
|
||||||
public final TextView itemUploaderView;
|
public final TextView itemUploaderView;
|
||||||
|
private final TextView itemStreamCountView;
|
||||||
|
|
||||||
public PlaylistMiniInfoItemHolder(final InfoItemBuilder infoItemBuilder, final int layoutId,
|
public PlaylistMiniInfoItemHolder(final InfoItemBuilder infoItemBuilder, final int layoutId,
|
||||||
final ViewGroup parent) {
|
final ViewGroup parent) {
|
||||||
|
@ -36,10 +35,9 @@ public class PlaylistMiniInfoItemHolder extends InfoItemHolder {
|
||||||
@Override
|
@Override
|
||||||
public void updateFromItem(final InfoItem infoItem,
|
public void updateFromItem(final InfoItem infoItem,
|
||||||
final HistoryRecordManager historyRecordManager) {
|
final HistoryRecordManager historyRecordManager) {
|
||||||
if (!(infoItem instanceof PlaylistInfoItem)) {
|
if (!(infoItem instanceof final PlaylistInfoItem item)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
final PlaylistInfoItem item = (PlaylistInfoItem) infoItem;
|
|
||||||
|
|
||||||
itemTitleView.setText(item.getName());
|
itemTitleView.setText(item.getName());
|
||||||
itemStreamCountView.setText(Localization
|
itemStreamCountView.setText(Localization
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package org.schabi.newpipe.info_list.holder;
|
package org.schabi.newpipe.info_list.holder;
|
||||||
|
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
|
||||||
import org.schabi.newpipe.R;
|
import org.schabi.newpipe.R;
|
||||||
import org.schabi.newpipe.info_list.InfoItemBuilder;
|
import org.schabi.newpipe.info_list.InfoItemBuilder;
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package org.schabi.newpipe.info_list.holder;
|
package org.schabi.newpipe.info_list.holder;
|
||||||
|
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
|
||||||
import org.schabi.newpipe.R;
|
import org.schabi.newpipe.R;
|
||||||
import org.schabi.newpipe.info_list.InfoItemBuilder;
|
import org.schabi.newpipe.info_list.InfoItemBuilder;
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@ package org.schabi.newpipe.info_list.holder;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
import androidx.preference.PreferenceManager;
|
||||||
import org.schabi.newpipe.R;
|
import org.schabi.newpipe.R;
|
||||||
import org.schabi.newpipe.extractor.InfoItem;
|
import org.schabi.newpipe.extractor.InfoItem;
|
||||||
import org.schabi.newpipe.extractor.stream.StreamInfoItem;
|
import org.schabi.newpipe.extractor.stream.StreamInfoItem;
|
||||||
|
@ -12,8 +12,6 @@ import org.schabi.newpipe.info_list.InfoItemBuilder;
|
||||||
import org.schabi.newpipe.local.history.HistoryRecordManager;
|
import org.schabi.newpipe.local.history.HistoryRecordManager;
|
||||||
import org.schabi.newpipe.util.Localization;
|
import org.schabi.newpipe.util.Localization;
|
||||||
|
|
||||||
import androidx.preference.PreferenceManager;
|
|
||||||
|
|
||||||
import static org.schabi.newpipe.MainActivity.DEBUG;
|
import static org.schabi.newpipe.MainActivity.DEBUG;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -58,10 +56,9 @@ public class StreamInfoItemHolder extends StreamMiniInfoItemHolder {
|
||||||
final HistoryRecordManager historyRecordManager) {
|
final HistoryRecordManager historyRecordManager) {
|
||||||
super.updateFromItem(infoItem, historyRecordManager);
|
super.updateFromItem(infoItem, historyRecordManager);
|
||||||
|
|
||||||
if (!(infoItem instanceof StreamInfoItem)) {
|
if (!(infoItem instanceof final StreamInfoItem item)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
final StreamInfoItem item = (StreamInfoItem) infoItem;
|
|
||||||
|
|
||||||
itemAdditionalDetails.setText(getStreamInfoDetailLine(item));
|
itemAdditionalDetails.setText(getStreamInfoDetailLine(item));
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,9 +4,7 @@ import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import androidx.core.content.ContextCompat;
|
import androidx.core.content.ContextCompat;
|
||||||
|
|
||||||
import org.schabi.newpipe.R;
|
import org.schabi.newpipe.R;
|
||||||
import org.schabi.newpipe.database.stream.model.StreamStateEntity;
|
import org.schabi.newpipe.database.stream.model.StreamStateEntity;
|
||||||
import org.schabi.newpipe.extractor.InfoItem;
|
import org.schabi.newpipe.extractor.InfoItem;
|
||||||
|
@ -46,10 +44,9 @@ public class StreamMiniInfoItemHolder extends InfoItemHolder {
|
||||||
@Override
|
@Override
|
||||||
public void updateFromItem(final InfoItem infoItem,
|
public void updateFromItem(final InfoItem infoItem,
|
||||||
final HistoryRecordManager historyRecordManager) {
|
final HistoryRecordManager historyRecordManager) {
|
||||||
if (!(infoItem instanceof StreamInfoItem)) {
|
if (!(infoItem instanceof final StreamInfoItem item)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
final StreamInfoItem item = (StreamInfoItem) infoItem;
|
|
||||||
|
|
||||||
itemVideoTitleView.setText(item.getName());
|
itemVideoTitleView.setText(item.getName());
|
||||||
itemUploaderView.setText(item.getUploaderName());
|
itemUploaderView.setText(item.getUploaderName());
|
||||||
|
|
|
@ -7,7 +7,6 @@ import android.util.Log;
|
||||||
import android.view.Menu;
|
import android.view.Menu;
|
||||||
import android.view.MenuInflater;
|
import android.view.MenuInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.appcompat.app.ActionBar;
|
import androidx.appcompat.app.ActionBar;
|
||||||
|
@ -17,7 +16,6 @@ import androidx.recyclerview.widget.GridLayoutManager;
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
import androidx.viewbinding.ViewBinding;
|
import androidx.viewbinding.ViewBinding;
|
||||||
|
|
||||||
import org.schabi.newpipe.R;
|
import org.schabi.newpipe.R;
|
||||||
import org.schabi.newpipe.databinding.PignateFooterBinding;
|
import org.schabi.newpipe.databinding.PignateFooterBinding;
|
||||||
import org.schabi.newpipe.fragments.BaseStateFragment;
|
import org.schabi.newpipe.fragments.BaseStateFragment;
|
||||||
|
@ -48,10 +46,10 @@ public abstract class BaseLocalListFragment<I, N> extends BaseStateFragment<I>
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
private static final int LIST_MODE_UPDATE_FLAG = 0x32;
|
private static final int LIST_MODE_UPDATE_FLAG = 0x32;
|
||||||
private ViewBinding headerRootBinding;
|
|
||||||
private ViewBinding footerRootBinding;
|
|
||||||
protected LocalItemListAdapter itemListAdapter;
|
protected LocalItemListAdapter itemListAdapter;
|
||||||
protected RecyclerView itemsList;
|
protected RecyclerView itemsList;
|
||||||
|
private ViewBinding headerRootBinding;
|
||||||
|
private ViewBinding footerRootBinding;
|
||||||
private int updateFlags = 0;
|
private int updateFlags = 0;
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package org.schabi.newpipe.local;
|
package org.schabi.newpipe.local;
|
||||||
|
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
public class HeaderFooterHolder extends RecyclerView.ViewHolder {
|
public class HeaderFooterHolder extends RecyclerView.ViewHolder {
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package org.schabi.newpipe.local;
|
package org.schabi.newpipe.local;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
|
||||||
import org.schabi.newpipe.database.LocalItem;
|
import org.schabi.newpipe.database.LocalItem;
|
||||||
import org.schabi.newpipe.util.OnClickGesture;
|
import org.schabi.newpipe.util.OnClickGesture;
|
||||||
|
|
||||||
|
|
|
@ -4,29 +4,15 @@ import android.content.Context;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.recyclerview.widget.GridLayoutManager;
|
import androidx.recyclerview.widget.GridLayoutManager;
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
import org.schabi.newpipe.database.LocalItem;
|
import org.schabi.newpipe.database.LocalItem;
|
||||||
import org.schabi.newpipe.database.stream.model.StreamStateEntity;
|
import org.schabi.newpipe.database.stream.model.StreamStateEntity;
|
||||||
import org.schabi.newpipe.info_list.ItemViewMode;
|
import org.schabi.newpipe.info_list.ItemViewMode;
|
||||||
import org.schabi.newpipe.local.history.HistoryRecordManager;
|
import org.schabi.newpipe.local.history.HistoryRecordManager;
|
||||||
import org.schabi.newpipe.local.holder.LocalItemHolder;
|
import org.schabi.newpipe.local.holder.*;
|
||||||
import org.schabi.newpipe.local.holder.LocalPlaylistCardItemHolder;
|
|
||||||
import org.schabi.newpipe.local.holder.LocalPlaylistGridItemHolder;
|
|
||||||
import org.schabi.newpipe.local.holder.LocalPlaylistItemHolder;
|
|
||||||
import org.schabi.newpipe.local.holder.LocalPlaylistStreamCardItemHolder;
|
|
||||||
import org.schabi.newpipe.local.holder.LocalPlaylistStreamGridItemHolder;
|
|
||||||
import org.schabi.newpipe.local.holder.LocalPlaylistStreamItemHolder;
|
|
||||||
import org.schabi.newpipe.local.holder.LocalStatisticStreamCardItemHolder;
|
|
||||||
import org.schabi.newpipe.local.holder.LocalStatisticStreamGridItemHolder;
|
|
||||||
import org.schabi.newpipe.local.holder.LocalStatisticStreamItemHolder;
|
|
||||||
import org.schabi.newpipe.local.holder.RemotePlaylistCardItemHolder;
|
|
||||||
import org.schabi.newpipe.local.holder.RemotePlaylistGridItemHolder;
|
|
||||||
import org.schabi.newpipe.local.holder.RemotePlaylistItemHolder;
|
|
||||||
import org.schabi.newpipe.util.FallbackViewHolder;
|
import org.schabi.newpipe.util.FallbackViewHolder;
|
||||||
import org.schabi.newpipe.util.Localization;
|
import org.schabi.newpipe.util.Localization;
|
||||||
import org.schabi.newpipe.util.OnClickGesture;
|
import org.schabi.newpipe.util.OnClickGesture;
|
||||||
|
|
|
@ -8,12 +8,16 @@ 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;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.appcompat.app.AlertDialog;
|
import androidx.appcompat.app.AlertDialog;
|
||||||
import androidx.fragment.app.FragmentManager;
|
import androidx.fragment.app.FragmentManager;
|
||||||
|
import icepick.State;
|
||||||
|
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
|
||||||
|
import io.reactivex.rxjava3.core.Flowable;
|
||||||
|
import io.reactivex.rxjava3.core.Single;
|
||||||
|
import io.reactivex.rxjava3.disposables.CompositeDisposable;
|
||||||
|
import io.reactivex.rxjava3.disposables.Disposable;
|
||||||
import org.reactivestreams.Subscriber;
|
import org.reactivestreams.Subscriber;
|
||||||
import org.reactivestreams.Subscription;
|
import org.reactivestreams.Subscription;
|
||||||
import org.schabi.newpipe.NewPipeDatabase;
|
import org.schabi.newpipe.NewPipeDatabase;
|
||||||
|
@ -35,16 +39,9 @@ import org.schabi.newpipe.util.OnClickGesture;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import icepick.State;
|
|
||||||
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
|
|
||||||
import io.reactivex.rxjava3.core.Flowable;
|
|
||||||
import io.reactivex.rxjava3.core.Single;
|
|
||||||
import io.reactivex.rxjava3.disposables.CompositeDisposable;
|
|
||||||
import io.reactivex.rxjava3.disposables.Disposable;
|
|
||||||
|
|
||||||
public final class BookmarkFragment extends BaseLocalListFragment<List<PlaylistLocalItem>, Void> {
|
public final class BookmarkFragment extends BaseLocalListFragment<List<PlaylistLocalItem>, Void> {
|
||||||
@State
|
@State
|
||||||
protected Parcelable itemsListState;
|
private Parcelable itemsListState;
|
||||||
|
|
||||||
private Subscription databaseSubscription;
|
private Subscription databaseSubscription;
|
||||||
private CompositeDisposable disposables = new CompositeDisposable();
|
private CompositeDisposable disposables = new CompositeDisposable();
|
||||||
|
@ -105,13 +102,11 @@ public final class BookmarkFragment extends BaseLocalListFragment<List<PlaylistL
|
||||||
public void selected(final LocalItem selectedItem) {
|
public void selected(final LocalItem selectedItem) {
|
||||||
final FragmentManager fragmentManager = getFM();
|
final FragmentManager fragmentManager = getFM();
|
||||||
|
|
||||||
if (selectedItem instanceof PlaylistMetadataEntry) {
|
if (selectedItem instanceof final PlaylistMetadataEntry entry) {
|
||||||
final PlaylistMetadataEntry entry = ((PlaylistMetadataEntry) selectedItem);
|
|
||||||
NavigationHelper.openLocalPlaylistFragment(fragmentManager, entry.uid,
|
NavigationHelper.openLocalPlaylistFragment(fragmentManager, entry.uid,
|
||||||
entry.name);
|
entry.name);
|
||||||
|
|
||||||
} else if (selectedItem instanceof PlaylistRemoteEntity) {
|
} else if (selectedItem instanceof final PlaylistRemoteEntity entry) {
|
||||||
final PlaylistRemoteEntity entry = ((PlaylistRemoteEntity) selectedItem);
|
|
||||||
NavigationHelper.openPlaylistFragment(
|
NavigationHelper.openPlaylistFragment(
|
||||||
fragmentManager,
|
fragmentManager,
|
||||||
entry.getServiceId(),
|
entry.getServiceId(),
|
||||||
|
@ -140,7 +135,7 @@ public final class BookmarkFragment extends BaseLocalListFragment<List<PlaylistL
|
||||||
super.startLoading(forceLoad);
|
super.startLoading(forceLoad);
|
||||||
|
|
||||||
Flowable.combineLatest(localPlaylistManager.getPlaylists(),
|
Flowable.combineLatest(localPlaylistManager.getPlaylists(),
|
||||||
remotePlaylistManager.getPlaylists(), PlaylistLocalItem::merge)
|
remotePlaylistManager.getPlaylists(), PlaylistLocalItem::merge)
|
||||||
.onBackpressureLatest()
|
.onBackpressureLatest()
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
.subscribe(getPlaylistsSubscriber());
|
.subscribe(getPlaylistsSubscriber());
|
||||||
|
@ -214,7 +209,8 @@ public final class BookmarkFragment extends BaseLocalListFragment<List<PlaylistL
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onComplete() { }
|
public void onComplete() {
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,12 +5,12 @@ import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
|
||||||
|
import io.reactivex.rxjava3.disposables.CompositeDisposable;
|
||||||
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.PlaylistMetadataEntry;
|
import org.schabi.newpipe.database.playlist.PlaylistMetadataEntry;
|
||||||
|
@ -20,21 +20,16 @@ import org.schabi.newpipe.local.playlist.LocalPlaylistManager;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
|
|
||||||
import io.reactivex.rxjava3.disposables.CompositeDisposable;
|
|
||||||
|
|
||||||
public final class PlaylistAppendDialog extends PlaylistDialog {
|
public final class PlaylistAppendDialog extends PlaylistDialog {
|
||||||
private static final String TAG = PlaylistAppendDialog.class.getCanonicalName();
|
private static final String TAG = PlaylistAppendDialog.class.getCanonicalName();
|
||||||
|
private final CompositeDisposable playlistDisposables = new CompositeDisposable();
|
||||||
private RecyclerView playlistRecyclerView;
|
private RecyclerView playlistRecyclerView;
|
||||||
private LocalItemListAdapter playlistAdapter;
|
private LocalItemListAdapter playlistAdapter;
|
||||||
|
|
||||||
private final CompositeDisposable playlistDisposables = new CompositeDisposable();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new instance of {@link PlaylistAppendDialog}.
|
* Create a new instance of {@link PlaylistAppendDialog}.
|
||||||
*
|
*
|
||||||
* @param streamEntities a list of {@link StreamEntity} to be added to playlists
|
* @param streamEntities a list of {@link StreamEntity} to be added to playlists
|
||||||
* @return a new instance of {@link PlaylistAppendDialog}
|
* @return a new instance of {@link PlaylistAppendDialog}
|
||||||
*/
|
*/
|
||||||
public static PlaylistAppendDialog newInstance(final List<StreamEntity> streamEntities) {
|
public static PlaylistAppendDialog newInstance(final List<StreamEntity> streamEntities) {
|
||||||
|
@ -101,7 +96,9 @@ public final class PlaylistAppendDialog extends PlaylistDialog {
|
||||||
// Helper
|
// Helper
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
/** Display create playlist dialog. */
|
/**
|
||||||
|
* Display create playlist dialog.
|
||||||
|
*/
|
||||||
public void openCreatePlaylistDialog() {
|
public void openCreatePlaylistDialog() {
|
||||||
if (getStreamEntities() == null || !isAdded()) {
|
if (getStreamEntities() == null || !isAdded()) {
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -4,11 +4,10 @@ import android.app.Dialog;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.text.InputType;
|
import android.text.InputType;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.appcompat.app.AlertDialog.Builder;
|
import androidx.appcompat.app.AlertDialog.Builder;
|
||||||
|
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
|
||||||
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.stream.model.StreamEntity;
|
import org.schabi.newpipe.database.stream.model.StreamEntity;
|
||||||
|
@ -18,14 +17,12 @@ import org.schabi.newpipe.util.ThemeHelper;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
|
|
||||||
|
|
||||||
public final class PlaylistCreationDialog extends PlaylistDialog {
|
public final class PlaylistCreationDialog extends PlaylistDialog {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new instance of {@link PlaylistCreationDialog}.
|
* Create a new instance of {@link PlaylistCreationDialog}.
|
||||||
*
|
*
|
||||||
* @param streamEntities a list of {@link StreamEntity} to be added to playlists
|
* @param streamEntities a list of {@link StreamEntity} to be added to playlists
|
||||||
* @return a new instance of {@link PlaylistCreationDialog}
|
* @return a new instance of {@link PlaylistCreationDialog}
|
||||||
*/
|
*/
|
||||||
public static PlaylistCreationDialog newInstance(final List<StreamEntity> streamEntities) {
|
public static PlaylistCreationDialog newInstance(final List<StreamEntity> streamEntities) {
|
||||||
|
|
|
@ -5,12 +5,12 @@ import android.content.Context;
|
||||||
import android.content.DialogInterface;
|
import android.content.DialogInterface;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.view.Window;
|
import android.view.Window;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.fragment.app.DialogFragment;
|
import androidx.fragment.app.DialogFragment;
|
||||||
import androidx.fragment.app.FragmentManager;
|
import androidx.fragment.app.FragmentManager;
|
||||||
|
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
|
||||||
|
import io.reactivex.rxjava3.disposables.Disposable;
|
||||||
import org.schabi.newpipe.NewPipeDatabase;
|
import org.schabi.newpipe.NewPipeDatabase;
|
||||||
import org.schabi.newpipe.database.stream.model.StreamEntity;
|
import org.schabi.newpipe.database.stream.model.StreamEntity;
|
||||||
import org.schabi.newpipe.local.playlist.LocalPlaylistManager;
|
import org.schabi.newpipe.local.playlist.LocalPlaylistManager;
|
||||||
|
@ -24,9 +24,6 @@ import java.util.function.Consumer;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
|
|
||||||
import io.reactivex.rxjava3.disposables.Disposable;
|
|
||||||
|
|
||||||
public abstract class PlaylistDialog extends DialogFragment implements StateSaver.WriteRead {
|
public abstract class PlaylistDialog extends DialogFragment implements StateSaver.WriteRead {
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
|
@ -40,95 +37,6 @@ public abstract class PlaylistDialog extends DialogFragment implements StateSave
|
||||||
// LifeCycle
|
// LifeCycle
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onCreate(@Nullable final Bundle savedInstanceState) {
|
|
||||||
super.onCreate(savedInstanceState);
|
|
||||||
savedState = StateSaver.tryToRestore(savedInstanceState, this);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onDestroy() {
|
|
||||||
super.onDestroy();
|
|
||||||
StateSaver.onDestroy(savedState);
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<StreamEntity> getStreamEntities() {
|
|
||||||
return streamEntities;
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
@Override
|
|
||||||
public Dialog onCreateDialog(final Bundle savedInstanceState) {
|
|
||||||
final Dialog dialog = super.onCreateDialog(savedInstanceState);
|
|
||||||
//remove title
|
|
||||||
final Window window = dialog.getWindow();
|
|
||||||
if (window != null) {
|
|
||||||
window.requestFeature(Window.FEATURE_NO_TITLE);
|
|
||||||
}
|
|
||||||
return dialog;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onDismiss(@NonNull final DialogInterface dialog) {
|
|
||||||
super.onDismiss(dialog);
|
|
||||||
if (onDismissListener != null) {
|
|
||||||
onDismissListener.onDismiss(dialog);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
|
||||||
// State Saving
|
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String generateSuffix() {
|
|
||||||
final int size = streamEntities == null ? 0 : streamEntities.size();
|
|
||||||
return "." + size + ".list";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void writeTo(final Queue<Object> objectsToSave) {
|
|
||||||
objectsToSave.add(streamEntities);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public void readFrom(@NonNull final Queue<Object> savedObjects) {
|
|
||||||
streamEntities = (List<StreamEntity>) savedObjects.poll();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onSaveInstanceState(@NonNull final Bundle outState) {
|
|
||||||
super.onSaveInstanceState(outState);
|
|
||||||
if (getActivity() != null) {
|
|
||||||
savedState = StateSaver.tryToSave(getActivity().isChangingConfigurations(),
|
|
||||||
savedState, outState, this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
|
||||||
// Getter + Setter
|
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
public DialogInterface.OnDismissListener getOnDismissListener() {
|
|
||||||
return onDismissListener;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setOnDismissListener(
|
|
||||||
@Nullable final DialogInterface.OnDismissListener onDismissListener
|
|
||||||
) {
|
|
||||||
this.onDismissListener = onDismissListener;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void setStreamEntities(final List<StreamEntity> streamEntities) {
|
|
||||||
this.streamEntities = streamEntities;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
|
||||||
// Dialog creation
|
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a {@link PlaylistAppendDialog} when playlists exists,
|
* Creates a {@link PlaylistAppendDialog} when playlists exists,
|
||||||
* otherwise a {@link PlaylistCreationDialog}.
|
* otherwise a {@link PlaylistCreationDialog}.
|
||||||
|
@ -178,4 +86,93 @@ public abstract class PlaylistDialog extends DialogFragment implements StateSave
|
||||||
return PlaylistDialog.createCorrespondingDialog(player.getContext(), streamEntities,
|
return PlaylistDialog.createCorrespondingDialog(player.getContext(), streamEntities,
|
||||||
dialog -> dialog.show(fragmentManager, "PlaylistDialog"));
|
dialog -> dialog.show(fragmentManager, "PlaylistDialog"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreate(@Nullable final Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
savedState = StateSaver.tryToRestore(savedInstanceState, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDestroy() {
|
||||||
|
super.onDestroy();
|
||||||
|
StateSaver.onDestroy(savedState);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<StreamEntity> getStreamEntities() {
|
||||||
|
return streamEntities;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
|
// State Saving
|
||||||
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
|
protected void setStreamEntities(final List<StreamEntity> streamEntities) {
|
||||||
|
this.streamEntities = streamEntities;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
public Dialog onCreateDialog(final Bundle savedInstanceState) {
|
||||||
|
final Dialog dialog = super.onCreateDialog(savedInstanceState);
|
||||||
|
//remove title
|
||||||
|
final Window window = dialog.getWindow();
|
||||||
|
if (window != null) {
|
||||||
|
window.requestFeature(Window.FEATURE_NO_TITLE);
|
||||||
|
}
|
||||||
|
return dialog;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDismiss(@NonNull final DialogInterface dialog) {
|
||||||
|
super.onDismiss(dialog);
|
||||||
|
if (onDismissListener != null) {
|
||||||
|
onDismissListener.onDismiss(dialog);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String generateSuffix() {
|
||||||
|
final int size = streamEntities == null ? 0 : streamEntities.size();
|
||||||
|
return "." + size + ".list";
|
||||||
|
}
|
||||||
|
|
||||||
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
|
// Getter + Setter
|
||||||
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeTo(final Queue<Object> objectsToSave) {
|
||||||
|
objectsToSave.add(streamEntities);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public void readFrom(@NonNull final Queue<Object> savedObjects) {
|
||||||
|
streamEntities = (List<StreamEntity>) savedObjects.poll();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSaveInstanceState(@NonNull final Bundle outState) {
|
||||||
|
super.onSaveInstanceState(outState);
|
||||||
|
if (getActivity() != null) {
|
||||||
|
savedState = StateSaver.tryToSave(getActivity().isChangingConfigurations(),
|
||||||
|
savedState, outState, this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
|
// Dialog creation
|
||||||
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public DialogInterface.OnDismissListener getOnDismissListener() {
|
||||||
|
return onDismissListener;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOnDismissListener(
|
||||||
|
@Nullable final DialogInterface.OnDismissListener onDismissListener
|
||||||
|
) {
|
||||||
|
this.onDismissListener = onDismissListener;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,9 @@
|
||||||
package org.schabi.newpipe.local.history;
|
package org.schabi.newpipe.local.history;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
import org.schabi.newpipe.util.Localization;
|
import org.schabi.newpipe.util.Localization;
|
||||||
|
|
||||||
import java.text.DateFormat;
|
import java.text.DateFormat;
|
||||||
|
|
|
@ -20,10 +20,13 @@ package org.schabi.newpipe.local.history;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.preference.PreferenceManager;
|
import androidx.preference.PreferenceManager;
|
||||||
|
import io.reactivex.rxjava3.core.Completable;
|
||||||
|
import io.reactivex.rxjava3.core.Flowable;
|
||||||
|
import io.reactivex.rxjava3.core.Maybe;
|
||||||
|
import io.reactivex.rxjava3.core.Single;
|
||||||
|
import io.reactivex.rxjava3.schedulers.Schedulers;
|
||||||
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.AppDatabase;
|
import org.schabi.newpipe.database.AppDatabase;
|
||||||
|
@ -52,12 +55,6 @@ import java.time.ZoneOffset;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import io.reactivex.rxjava3.core.Completable;
|
|
||||||
import io.reactivex.rxjava3.core.Flowable;
|
|
||||||
import io.reactivex.rxjava3.core.Maybe;
|
|
||||||
import io.reactivex.rxjava3.core.Single;
|
|
||||||
import io.reactivex.rxjava3.schedulers.Schedulers;
|
|
||||||
|
|
||||||
public class HistoryRecordManager {
|
public class HistoryRecordManager {
|
||||||
private final AppDatabase database;
|
private final AppDatabase database;
|
||||||
private final StreamDAO streamTable;
|
private final StreamDAO streamTable;
|
||||||
|
@ -87,9 +84,9 @@ public class HistoryRecordManager {
|
||||||
* Marks a stream item as watched such that it is hidden from the feed if watched videos are
|
* Marks a stream item as watched such that it is hidden from the feed if watched videos are
|
||||||
* hidden. Adds a history entry and updates the stream progress to 100%.
|
* hidden. Adds a history entry and updates the stream progress to 100%.
|
||||||
*
|
*
|
||||||
* @see FeedViewModel#togglePlayedItems
|
|
||||||
* @param info the item to mark as watched
|
* @param info the item to mark as watched
|
||||||
* @return a Maybe containing the ID of the item if successful
|
* @return a Maybe containing the ID of the item if successful
|
||||||
|
* @see FeedViewModel#togglePlayedItems
|
||||||
*/
|
*/
|
||||||
public Maybe<Long> markAsWatched(final StreamInfoItem info) {
|
public Maybe<Long> markAsWatched(final StreamInfoItem info) {
|
||||||
if (!isStreamHistoryEnabled()) {
|
if (!isStreamHistoryEnabled()) {
|
||||||
|
@ -103,10 +100,10 @@ public class HistoryRecordManager {
|
||||||
// Duration will not exist if the item was loaded with fast mode, so fetch it if empty
|
// Duration will not exist if the item was loaded with fast mode, so fetch it if empty
|
||||||
if (info.getDuration() < 0) {
|
if (info.getDuration() < 0) {
|
||||||
final StreamInfo completeInfo = ExtractorHelper.getStreamInfo(
|
final StreamInfo completeInfo = ExtractorHelper.getStreamInfo(
|
||||||
info.getServiceId(),
|
info.getServiceId(),
|
||||||
info.getUrl(),
|
info.getUrl(),
|
||||||
false
|
false
|
||||||
)
|
)
|
||||||
.subscribeOn(Schedulers.io())
|
.subscribeOn(Schedulers.io())
|
||||||
.blockingGet();
|
.blockingGet();
|
||||||
duration = completeInfo.getDuration();
|
duration = completeInfo.getDuration();
|
||||||
|
|
|
@ -3,20 +3,16 @@ package org.schabi.newpipe.local.history;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Parcelable;
|
import android.os.Parcelable;
|
||||||
import android.view.LayoutInflater;
|
import android.view.*;
|
||||||
import android.view.Menu;
|
|
||||||
import android.view.MenuInflater;
|
|
||||||
import android.view.MenuItem;
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.ViewGroup;
|
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.viewbinding.ViewBinding;
|
import androidx.viewbinding.ViewBinding;
|
||||||
|
|
||||||
import com.google.android.material.snackbar.Snackbar;
|
import com.google.android.material.snackbar.Snackbar;
|
||||||
|
import icepick.State;
|
||||||
|
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
|
||||||
|
import io.reactivex.rxjava3.disposables.CompositeDisposable;
|
||||||
|
import io.reactivex.rxjava3.disposables.Disposable;
|
||||||
import org.reactivestreams.Subscriber;
|
import org.reactivestreams.Subscriber;
|
||||||
import org.reactivestreams.Subscription;
|
import org.reactivestreams.Subscription;
|
||||||
import org.schabi.newpipe.R;
|
import org.schabi.newpipe.R;
|
||||||
|
@ -29,24 +25,15 @@ import org.schabi.newpipe.error.ErrorInfo;
|
||||||
import org.schabi.newpipe.error.UserAction;
|
import org.schabi.newpipe.error.UserAction;
|
||||||
import org.schabi.newpipe.extractor.stream.StreamInfoItem;
|
import org.schabi.newpipe.extractor.stream.StreamInfoItem;
|
||||||
import org.schabi.newpipe.info_list.dialog.InfoItemDialog;
|
import org.schabi.newpipe.info_list.dialog.InfoItemDialog;
|
||||||
|
import org.schabi.newpipe.info_list.dialog.StreamDialogDefaultEntry;
|
||||||
import org.schabi.newpipe.local.BaseLocalListFragment;
|
import org.schabi.newpipe.local.BaseLocalListFragment;
|
||||||
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.settings.HistorySettingsFragment;
|
import org.schabi.newpipe.settings.HistorySettingsFragment;
|
||||||
import org.schabi.newpipe.util.NavigationHelper;
|
import org.schabi.newpipe.util.NavigationHelper;
|
||||||
import org.schabi.newpipe.util.OnClickGesture;
|
import org.schabi.newpipe.util.OnClickGesture;
|
||||||
import org.schabi.newpipe.info_list.dialog.StreamDialogDefaultEntry;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Comparator;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
import icepick.State;
|
|
||||||
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
|
|
||||||
import io.reactivex.rxjava3.disposables.CompositeDisposable;
|
|
||||||
import io.reactivex.rxjava3.disposables.Disposable;
|
|
||||||
|
|
||||||
public class StatisticsPlaylistFragment
|
public class StatisticsPlaylistFragment
|
||||||
extends BaseLocalListFragment<List<StreamStatisticsEntry>, Void> {
|
extends BaseLocalListFragment<List<StreamStatisticsEntry>, Void> {
|
||||||
|
@ -313,7 +300,7 @@ public class StatisticsPlaylistFragment
|
||||||
sortMode = StatisticSortMode.LAST_PLAYED;
|
sortMode = StatisticSortMode.LAST_PLAYED;
|
||||||
setTitle(getString(R.string.title_last_played));
|
setTitle(getString(R.string.title_last_played));
|
||||||
headerBinding.sortButtonIcon.setImageResource(
|
headerBinding.sortButtonIcon.setImageResource(
|
||||||
R.drawable.ic_filter_list);
|
R.drawable.ic_filter_list);
|
||||||
headerBinding.sortButtonText.setText(R.string.title_most_played);
|
headerBinding.sortButtonText.setText(R.string.title_most_played);
|
||||||
}
|
}
|
||||||
startLoading(true);
|
startLoading(true);
|
||||||
|
@ -351,8 +338,7 @@ public class StatisticsPlaylistFragment
|
||||||
|
|
||||||
private void deleteEntry(final int index) {
|
private void deleteEntry(final int index) {
|
||||||
final LocalItem infoItem = itemListAdapter.getItemsList().get(index);
|
final LocalItem infoItem = itemListAdapter.getItemsList().get(index);
|
||||||
if (infoItem instanceof StreamStatisticsEntry) {
|
if (infoItem instanceof final StreamStatisticsEntry entry) {
|
||||||
final StreamStatisticsEntry entry = (StreamStatisticsEntry) infoItem;
|
|
||||||
final Disposable onDelete = recordManager
|
final Disposable onDelete = recordManager
|
||||||
.deleteStreamHistoryAndState(entry.getStreamId())
|
.deleteStreamHistoryAndState(entry.getStreamId())
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
|
|
|
@ -2,9 +2,7 @@ package org.schabi.newpipe.local.holder;
|
||||||
|
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
import org.schabi.newpipe.database.LocalItem;
|
import org.schabi.newpipe.database.LocalItem;
|
||||||
import org.schabi.newpipe.local.LocalItemBuilder;
|
import org.schabi.newpipe.local.LocalItemBuilder;
|
||||||
import org.schabi.newpipe.local.history.HistoryRecordManager;
|
import org.schabi.newpipe.local.history.HistoryRecordManager;
|
||||||
|
@ -44,5 +42,6 @@ public abstract class LocalItemHolder extends RecyclerView.ViewHolder {
|
||||||
DateTimeFormatter dateTimeFormatter);
|
DateTimeFormatter dateTimeFormatter);
|
||||||
|
|
||||||
public void updateState(final LocalItem localItem,
|
public void updateState(final LocalItem localItem,
|
||||||
final HistoryRecordManager historyRecordManager) { }
|
final HistoryRecordManager historyRecordManager) {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package org.schabi.newpipe.local.holder;
|
package org.schabi.newpipe.local.holder;
|
||||||
|
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
|
||||||
import org.schabi.newpipe.R;
|
import org.schabi.newpipe.R;
|
||||||
import org.schabi.newpipe.local.LocalItemBuilder;
|
import org.schabi.newpipe.local.LocalItemBuilder;
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package org.schabi.newpipe.local.holder;
|
package org.schabi.newpipe.local.holder;
|
||||||
|
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
|
||||||
import org.schabi.newpipe.R;
|
import org.schabi.newpipe.R;
|
||||||
import org.schabi.newpipe.local.LocalItemBuilder;
|
import org.schabi.newpipe.local.LocalItemBuilder;
|
||||||
|
|
||||||
|
|
|
@ -2,13 +2,12 @@ package org.schabi.newpipe.local.holder;
|
||||||
|
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
|
||||||
import org.schabi.newpipe.database.LocalItem;
|
import org.schabi.newpipe.database.LocalItem;
|
||||||
import org.schabi.newpipe.database.playlist.PlaylistMetadataEntry;
|
import org.schabi.newpipe.database.playlist.PlaylistMetadataEntry;
|
||||||
import org.schabi.newpipe.local.LocalItemBuilder;
|
import org.schabi.newpipe.local.LocalItemBuilder;
|
||||||
import org.schabi.newpipe.local.history.HistoryRecordManager;
|
import org.schabi.newpipe.local.history.HistoryRecordManager;
|
||||||
import org.schabi.newpipe.util.PicassoHelper;
|
|
||||||
import org.schabi.newpipe.util.Localization;
|
import org.schabi.newpipe.util.Localization;
|
||||||
|
import org.schabi.newpipe.util.PicassoHelper;
|
||||||
|
|
||||||
import java.time.format.DateTimeFormatter;
|
import java.time.format.DateTimeFormatter;
|
||||||
|
|
||||||
|
@ -26,10 +25,9 @@ public class LocalPlaylistItemHolder extends PlaylistItemHolder {
|
||||||
public void updateFromItem(final LocalItem localItem,
|
public void updateFromItem(final LocalItem localItem,
|
||||||
final HistoryRecordManager historyRecordManager,
|
final HistoryRecordManager historyRecordManager,
|
||||||
final DateTimeFormatter dateTimeFormatter) {
|
final DateTimeFormatter dateTimeFormatter) {
|
||||||
if (!(localItem instanceof PlaylistMetadataEntry)) {
|
if (!(localItem instanceof final PlaylistMetadataEntry item)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
final PlaylistMetadataEntry item = (PlaylistMetadataEntry) localItem;
|
|
||||||
|
|
||||||
itemTitleView.setText(item.name);
|
itemTitleView.setText(item.name);
|
||||||
itemStreamCountView.setText(Localization.localizeStreamCountMini(
|
itemStreamCountView.setText(Localization.localizeStreamCountMini(
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package org.schabi.newpipe.local.holder;
|
package org.schabi.newpipe.local.holder;
|
||||||
|
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
|
||||||
import org.schabi.newpipe.R;
|
import org.schabi.newpipe.R;
|
||||||
import org.schabi.newpipe.local.LocalItemBuilder;
|
import org.schabi.newpipe.local.LocalItemBuilder;
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package org.schabi.newpipe.local.holder;
|
package org.schabi.newpipe.local.holder;
|
||||||
|
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
|
||||||
import org.schabi.newpipe.R;
|
import org.schabi.newpipe.R;
|
||||||
import org.schabi.newpipe.local.LocalItemBuilder;
|
import org.schabi.newpipe.local.LocalItemBuilder;
|
||||||
|
|
||||||
|
|
|
@ -5,9 +5,7 @@ import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import androidx.core.content.ContextCompat;
|
import androidx.core.content.ContextCompat;
|
||||||
|
|
||||||
import org.schabi.newpipe.R;
|
import org.schabi.newpipe.R;
|
||||||
import org.schabi.newpipe.database.LocalItem;
|
import org.schabi.newpipe.database.LocalItem;
|
||||||
import org.schabi.newpipe.database.playlist.PlaylistStreamEntry;
|
import org.schabi.newpipe.database.playlist.PlaylistStreamEntry;
|
||||||
|
@ -25,8 +23,8 @@ import java.util.concurrent.TimeUnit;
|
||||||
public class LocalPlaylistStreamItemHolder extends LocalItemHolder {
|
public class LocalPlaylistStreamItemHolder extends LocalItemHolder {
|
||||||
public final ImageView itemThumbnailView;
|
public final ImageView itemThumbnailView;
|
||||||
public final TextView itemVideoTitleView;
|
public final TextView itemVideoTitleView;
|
||||||
private final TextView itemAdditionalDetailsView;
|
|
||||||
public final TextView itemDurationView;
|
public final TextView itemDurationView;
|
||||||
|
private final TextView itemAdditionalDetailsView;
|
||||||
private final View itemHandleView;
|
private final View itemHandleView;
|
||||||
private final AnimatedProgressBar itemProgressView;
|
private final AnimatedProgressBar itemProgressView;
|
||||||
|
|
||||||
|
@ -51,10 +49,9 @@ public class LocalPlaylistStreamItemHolder extends LocalItemHolder {
|
||||||
public void updateFromItem(final LocalItem localItem,
|
public void updateFromItem(final LocalItem localItem,
|
||||||
final HistoryRecordManager historyRecordManager,
|
final HistoryRecordManager historyRecordManager,
|
||||||
final DateTimeFormatter dateTimeFormatter) {
|
final DateTimeFormatter dateTimeFormatter) {
|
||||||
if (!(localItem instanceof PlaylistStreamEntry)) {
|
if (!(localItem instanceof final PlaylistStreamEntry item)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
final PlaylistStreamEntry item = (PlaylistStreamEntry) localItem;
|
|
||||||
|
|
||||||
itemVideoTitleView.setText(item.getStreamEntity().getTitle());
|
itemVideoTitleView.setText(item.getStreamEntity().getTitle());
|
||||||
itemAdditionalDetailsView.setText(Localization
|
itemAdditionalDetailsView.setText(Localization
|
||||||
|
@ -104,10 +101,9 @@ public class LocalPlaylistStreamItemHolder extends LocalItemHolder {
|
||||||
@Override
|
@Override
|
||||||
public void updateState(final LocalItem localItem,
|
public void updateState(final LocalItem localItem,
|
||||||
final HistoryRecordManager historyRecordManager) {
|
final HistoryRecordManager historyRecordManager) {
|
||||||
if (!(localItem instanceof PlaylistStreamEntry)) {
|
if (!(localItem instanceof final PlaylistStreamEntry item)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
final PlaylistStreamEntry item = (PlaylistStreamEntry) localItem;
|
|
||||||
|
|
||||||
if (item.getProgressMillis() > 0 && item.getStreamEntity().getDuration() > 0) {
|
if (item.getProgressMillis() > 0 && item.getStreamEntity().getDuration() > 0) {
|
||||||
itemProgressView.setMax((int) item.getStreamEntity().getDuration());
|
itemProgressView.setMax((int) item.getStreamEntity().getDuration());
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package org.schabi.newpipe.local.holder;
|
package org.schabi.newpipe.local.holder;
|
||||||
|
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
|
||||||
import org.schabi.newpipe.R;
|
import org.schabi.newpipe.R;
|
||||||
import org.schabi.newpipe.local.LocalItemBuilder;
|
import org.schabi.newpipe.local.LocalItemBuilder;
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package org.schabi.newpipe.local.holder;
|
package org.schabi.newpipe.local.holder;
|
||||||
|
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
|
||||||
import org.schabi.newpipe.R;
|
import org.schabi.newpipe.R;
|
||||||
import org.schabi.newpipe.local.LocalItemBuilder;
|
import org.schabi.newpipe.local.LocalItemBuilder;
|
||||||
|
|
||||||
|
|
|
@ -4,10 +4,8 @@ import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.core.content.ContextCompat;
|
import androidx.core.content.ContextCompat;
|
||||||
|
|
||||||
import org.schabi.newpipe.R;
|
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;
|
||||||
|
@ -82,10 +80,9 @@ public class LocalStatisticStreamItemHolder extends LocalItemHolder {
|
||||||
public void updateFromItem(final LocalItem localItem,
|
public void updateFromItem(final LocalItem localItem,
|
||||||
final HistoryRecordManager historyRecordManager,
|
final HistoryRecordManager historyRecordManager,
|
||||||
final DateTimeFormatter dateTimeFormatter) {
|
final DateTimeFormatter dateTimeFormatter) {
|
||||||
if (!(localItem instanceof StreamStatisticsEntry)) {
|
if (!(localItem instanceof final StreamStatisticsEntry item)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
final StreamStatisticsEntry item = (StreamStatisticsEntry) localItem;
|
|
||||||
|
|
||||||
itemVideoTitleView.setText(item.getStreamEntity().getTitle());
|
itemVideoTitleView.setText(item.getStreamEntity().getTitle());
|
||||||
itemUploaderView.setText(item.getStreamEntity().getUploader());
|
itemUploaderView.setText(item.getStreamEntity().getUploader());
|
||||||
|
@ -136,10 +133,9 @@ public class LocalStatisticStreamItemHolder extends LocalItemHolder {
|
||||||
@Override
|
@Override
|
||||||
public void updateState(final LocalItem localItem,
|
public void updateState(final LocalItem localItem,
|
||||||
final HistoryRecordManager historyRecordManager) {
|
final HistoryRecordManager historyRecordManager) {
|
||||||
if (!(localItem instanceof StreamStatisticsEntry)) {
|
if (!(localItem instanceof final StreamStatisticsEntry item)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
final StreamStatisticsEntry item = (StreamStatisticsEntry) localItem;
|
|
||||||
|
|
||||||
if (item.getProgressMillis() > 0 && item.getStreamEntity().getDuration() > 0) {
|
if (item.getProgressMillis() > 0 && item.getStreamEntity().getDuration() > 0) {
|
||||||
itemProgressView.setMax((int) item.getStreamEntity().getDuration());
|
itemProgressView.setMax((int) item.getStreamEntity().getDuration());
|
||||||
|
|
|
@ -3,7 +3,6 @@ package org.schabi.newpipe.local.holder;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.widget.ImageView;
|
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.database.LocalItem;
|
import org.schabi.newpipe.database.LocalItem;
|
||||||
import org.schabi.newpipe.local.LocalItemBuilder;
|
import org.schabi.newpipe.local.LocalItemBuilder;
|
||||||
|
@ -13,9 +12,9 @@ import java.time.format.DateTimeFormatter;
|
||||||
|
|
||||||
public abstract class PlaylistItemHolder extends LocalItemHolder {
|
public abstract class PlaylistItemHolder extends LocalItemHolder {
|
||||||
public final ImageView itemThumbnailView;
|
public final ImageView itemThumbnailView;
|
||||||
final TextView itemStreamCountView;
|
|
||||||
public final TextView itemTitleView;
|
public final TextView itemTitleView;
|
||||||
public final TextView itemUploaderView;
|
public final TextView itemUploaderView;
|
||||||
|
final TextView itemStreamCountView;
|
||||||
|
|
||||||
public PlaylistItemHolder(final LocalItemBuilder infoItemBuilder, final int layoutId,
|
public PlaylistItemHolder(final LocalItemBuilder infoItemBuilder, final int layoutId,
|
||||||
final ViewGroup parent) {
|
final ViewGroup parent) {
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package org.schabi.newpipe.local.holder;
|
package org.schabi.newpipe.local.holder;
|
||||||
|
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
|
||||||
import org.schabi.newpipe.R;
|
import org.schabi.newpipe.R;
|
||||||
import org.schabi.newpipe.local.LocalItemBuilder;
|
import org.schabi.newpipe.local.LocalItemBuilder;
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package org.schabi.newpipe.local.holder;
|
package org.schabi.newpipe.local.holder;
|
||||||
|
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
|
||||||
import org.schabi.newpipe.R;
|
import org.schabi.newpipe.R;
|
||||||
import org.schabi.newpipe.local.LocalItemBuilder;
|
import org.schabi.newpipe.local.LocalItemBuilder;
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,6 @@ package org.schabi.newpipe.local.holder;
|
||||||
|
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
|
||||||
import org.schabi.newpipe.database.LocalItem;
|
import org.schabi.newpipe.database.LocalItem;
|
||||||
import org.schabi.newpipe.database.playlist.model.PlaylistRemoteEntity;
|
import org.schabi.newpipe.database.playlist.model.PlaylistRemoteEntity;
|
||||||
import org.schabi.newpipe.local.LocalItemBuilder;
|
import org.schabi.newpipe.local.LocalItemBuilder;
|
||||||
|
@ -28,10 +27,9 @@ public class RemotePlaylistItemHolder extends PlaylistItemHolder {
|
||||||
public void updateFromItem(final LocalItem localItem,
|
public void updateFromItem(final LocalItem localItem,
|
||||||
final HistoryRecordManager historyRecordManager,
|
final HistoryRecordManager historyRecordManager,
|
||||||
final DateTimeFormatter dateTimeFormatter) {
|
final DateTimeFormatter dateTimeFormatter) {
|
||||||
if (!(localItem instanceof PlaylistRemoteEntity)) {
|
if (!(localItem instanceof final PlaylistRemoteEntity item)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
final PlaylistRemoteEntity item = (PlaylistRemoteEntity) localItem;
|
|
||||||
|
|
||||||
itemTitleView.setText(item.getName());
|
itemTitleView.setText(item.getName());
|
||||||
itemStreamCountView.setText(Localization.localizeStreamCountMini(
|
itemStreamCountView.setText(Localization.localizeStreamCountMini(
|
||||||
|
|
|
@ -1,9 +1,5 @@
|
||||||
package org.schabi.newpipe.local.playlist;
|
package org.schabi.newpipe.local.playlist;
|
||||||
|
|
||||||
import static org.schabi.newpipe.error.ErrorUtil.showUiErrorSnackbar;
|
|
||||||
import static org.schabi.newpipe.ktx.ViewUtils.animate;
|
|
||||||
import static org.schabi.newpipe.util.ThemeHelper.shouldUseGridLayout;
|
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.DialogInterface;
|
import android.content.DialogInterface;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
@ -12,14 +8,8 @@ import android.text.InputType;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.util.Pair;
|
import android.util.Pair;
|
||||||
import android.view.LayoutInflater;
|
import android.view.*;
|
||||||
import android.view.Menu;
|
|
||||||
import android.view.MenuInflater;
|
|
||||||
import android.view.MenuItem;
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.ViewGroup;
|
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.appcompat.app.AlertDialog;
|
import androidx.appcompat.app.AlertDialog;
|
||||||
|
@ -27,7 +17,13 @@ import androidx.preference.PreferenceManager;
|
||||||
import androidx.recyclerview.widget.ItemTouchHelper;
|
import androidx.recyclerview.widget.ItemTouchHelper;
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
import androidx.viewbinding.ViewBinding;
|
import androidx.viewbinding.ViewBinding;
|
||||||
|
import icepick.State;
|
||||||
|
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
|
||||||
|
import io.reactivex.rxjava3.core.Single;
|
||||||
|
import io.reactivex.rxjava3.disposables.CompositeDisposable;
|
||||||
|
import io.reactivex.rxjava3.disposables.Disposable;
|
||||||
|
import io.reactivex.rxjava3.schedulers.Schedulers;
|
||||||
|
import io.reactivex.rxjava3.subjects.PublishSubject;
|
||||||
import org.reactivestreams.Subscriber;
|
import org.reactivestreams.Subscriber;
|
||||||
import org.reactivestreams.Subscription;
|
import org.reactivestreams.Subscription;
|
||||||
import org.schabi.newpipe.NewPipeDatabase;
|
import org.schabi.newpipe.NewPipeDatabase;
|
||||||
|
@ -61,13 +57,9 @@ import java.util.concurrent.TimeUnit;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import icepick.State;
|
import static org.schabi.newpipe.error.ErrorUtil.showUiErrorSnackbar;
|
||||||
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
|
import static org.schabi.newpipe.ktx.ViewUtils.animate;
|
||||||
import io.reactivex.rxjava3.core.Single;
|
import static org.schabi.newpipe.util.ThemeHelper.shouldUseGridLayout;
|
||||||
import io.reactivex.rxjava3.disposables.CompositeDisposable;
|
|
||||||
import io.reactivex.rxjava3.disposables.Disposable;
|
|
||||||
import io.reactivex.rxjava3.schedulers.Schedulers;
|
|
||||||
import io.reactivex.rxjava3.subjects.PublishSubject;
|
|
||||||
|
|
||||||
public class LocalPlaylistFragment extends BaseLocalListFragment<List<PlaylistStreamEntry>, Void> {
|
public class LocalPlaylistFragment extends BaseLocalListFragment<List<PlaylistStreamEntry>, Void> {
|
||||||
// Save the list 10 seconds after the last change occurred
|
// Save the list 10 seconds after the last change occurred
|
||||||
|
|
|
@ -1,7 +1,11 @@
|
||||||
package org.schabi.newpipe.local.playlist;
|
package org.schabi.newpipe.local.playlist;
|
||||||
|
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
import io.reactivex.rxjava3.core.Completable;
|
||||||
|
import io.reactivex.rxjava3.core.Flowable;
|
||||||
|
import io.reactivex.rxjava3.core.Maybe;
|
||||||
|
import io.reactivex.rxjava3.core.Single;
|
||||||
|
import io.reactivex.rxjava3.schedulers.Schedulers;
|
||||||
import org.schabi.newpipe.R;
|
import org.schabi.newpipe.R;
|
||||||
import org.schabi.newpipe.database.AppDatabase;
|
import org.schabi.newpipe.database.AppDatabase;
|
||||||
import org.schabi.newpipe.database.playlist.PlaylistMetadataEntry;
|
import org.schabi.newpipe.database.playlist.PlaylistMetadataEntry;
|
||||||
|
@ -16,12 +20,6 @@ import org.schabi.newpipe.database.stream.model.StreamEntity;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import io.reactivex.rxjava3.core.Completable;
|
|
||||||
import io.reactivex.rxjava3.core.Flowable;
|
|
||||||
import io.reactivex.rxjava3.core.Maybe;
|
|
||||||
import io.reactivex.rxjava3.core.Single;
|
|
||||||
import io.reactivex.rxjava3.schedulers.Schedulers;
|
|
||||||
|
|
||||||
public class LocalPlaylistManager {
|
public class LocalPlaylistManager {
|
||||||
private final AppDatabase database;
|
private final AppDatabase database;
|
||||||
private final StreamDAO streamTable;
|
private final StreamDAO streamTable;
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
package org.schabi.newpipe.local.playlist;
|
package org.schabi.newpipe.local.playlist;
|
||||||
|
|
||||||
|
import io.reactivex.rxjava3.core.Flowable;
|
||||||
|
import io.reactivex.rxjava3.core.Single;
|
||||||
|
import io.reactivex.rxjava3.schedulers.Schedulers;
|
||||||
import org.schabi.newpipe.database.AppDatabase;
|
import org.schabi.newpipe.database.AppDatabase;
|
||||||
import org.schabi.newpipe.database.playlist.dao.PlaylistRemoteDAO;
|
import org.schabi.newpipe.database.playlist.dao.PlaylistRemoteDAO;
|
||||||
import org.schabi.newpipe.database.playlist.model.PlaylistRemoteEntity;
|
import org.schabi.newpipe.database.playlist.model.PlaylistRemoteEntity;
|
||||||
|
@ -7,10 +10,6 @@ import org.schabi.newpipe.extractor.playlist.PlaylistInfo;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import io.reactivex.rxjava3.core.Flowable;
|
|
||||||
import io.reactivex.rxjava3.core.Single;
|
|
||||||
import io.reactivex.rxjava3.schedulers.Schedulers;
|
|
||||||
|
|
||||||
public class RemotePlaylistManager {
|
public class RemotePlaylistManager {
|
||||||
|
|
||||||
private final PlaylistRemoteDAO playlistRemoteTable;
|
private final PlaylistRemoteDAO playlistRemoteTable;
|
||||||
|
|
|
@ -3,17 +3,14 @@ package org.schabi.newpipe.local.subscription;
|
||||||
import android.app.Dialog;
|
import android.app.Dialog;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.appcompat.app.AlertDialog;
|
import androidx.appcompat.app.AlertDialog;
|
||||||
import androidx.fragment.app.DialogFragment;
|
import androidx.fragment.app.DialogFragment;
|
||||||
import androidx.fragment.app.Fragment;
|
import androidx.fragment.app.Fragment;
|
||||||
|
|
||||||
import org.schabi.newpipe.R;
|
|
||||||
|
|
||||||
import icepick.Icepick;
|
import icepick.Icepick;
|
||||||
import icepick.State;
|
import icepick.State;
|
||||||
|
import org.schabi.newpipe.R;
|
||||||
|
|
||||||
import static org.schabi.newpipe.util.Localization.assureCorrectAppLanguage;
|
import static org.schabi.newpipe.util.Localization.assureCorrectAppLanguage;
|
||||||
|
|
||||||
|
@ -25,7 +22,7 @@ public class ImportConfirmationDialog extends DialogFragment {
|
||||||
@NonNull final Intent resultServiceIntent) {
|
@NonNull final Intent resultServiceIntent) {
|
||||||
final ImportConfirmationDialog confirmationDialog = new ImportConfirmationDialog();
|
final ImportConfirmationDialog confirmationDialog = new ImportConfirmationDialog();
|
||||||
confirmationDialog.setResultServiceIntent(resultServiceIntent);
|
confirmationDialog.setResultServiceIntent(resultServiceIntent);
|
||||||
confirmationDialog.show(fragment.getParentFragmentManager(), null);
|
show(fragment.getParentFragmentManager(), null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setResultServiceIntent(final Intent resultServiceIntent) {
|
public void setResultServiceIntent(final Intent resultServiceIntent) {
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue