2017-04-09 19:34:00 +02:00
|
|
|
package org.schabi.newpipe.fragments.detail;
|
2015-09-04 02:15:03 +02:00
|
|
|
|
2019-12-29 22:15:01 +01:00
|
|
|
import android.animation.ValueAnimator;
|
2017-04-09 19:34:00 +02:00
|
|
|
import android.app.Activity;
|
2020-07-14 19:21:32 +02:00
|
|
|
import android.content.BroadcastReceiver;
|
|
|
|
import android.content.Context;
|
|
|
|
import android.content.Intent;
|
|
|
|
import android.content.IntentFilter;
|
|
|
|
import android.content.SharedPreferences;
|
2019-12-29 22:15:01 +01:00
|
|
|
import android.content.pm.ActivityInfo;
|
2020-01-16 12:20:22 +01:00
|
|
|
import android.database.ContentObserver;
|
2020-09-15 13:43:43 +02:00
|
|
|
import android.graphics.Color;
|
2020-04-02 08:25:47 +02:00
|
|
|
import android.graphics.drawable.Drawable;
|
2017-03-31 20:15:26 +02:00
|
|
|
import android.os.Build;
|
2015-09-04 02:15:03 +02:00
|
|
|
import android.os.Bundle;
|
2019-12-29 22:15:01 +01:00
|
|
|
import android.os.Handler;
|
2020-09-17 22:42:35 +02:00
|
|
|
import android.os.Looper;
|
2019-12-29 22:15:01 +01:00
|
|
|
import android.provider.Settings;
|
2020-08-16 10:24:58 +02:00
|
|
|
import android.text.util.Linkify;
|
|
|
|
import android.util.DisplayMetrics;
|
|
|
|
import android.util.Log;
|
2020-07-14 19:21:32 +02:00
|
|
|
import android.view.LayoutInflater;
|
|
|
|
import android.view.MotionEvent;
|
|
|
|
import android.view.View;
|
|
|
|
import android.view.ViewGroup;
|
2020-10-31 21:55:45 +01:00
|
|
|
import android.view.ViewTreeObserver;
|
2020-07-14 19:21:32 +02:00
|
|
|
import android.view.WindowManager;
|
2019-12-29 22:15:01 +01:00
|
|
|
import android.view.animation.DecelerateInterpolator;
|
2020-07-14 19:21:32 +02:00
|
|
|
import android.widget.FrameLayout;
|
|
|
|
import android.widget.ImageButton;
|
|
|
|
import android.widget.ImageView;
|
|
|
|
import android.widget.LinearLayout;
|
|
|
|
import android.widget.RelativeLayout;
|
|
|
|
import android.widget.TextView;
|
2020-08-16 10:24:58 +02:00
|
|
|
|
2019-10-04 14:59:08 +02:00
|
|
|
import androidx.annotation.DrawableRes;
|
|
|
|
import androidx.annotation.NonNull;
|
|
|
|
import androidx.annotation.Nullable;
|
2020-03-10 10:06:38 +01:00
|
|
|
import androidx.appcompat.app.AlertDialog;
|
2020-08-16 10:24:58 +02:00
|
|
|
import androidx.appcompat.app.AppCompatActivity;
|
|
|
|
import androidx.appcompat.content.res.AppCompatResources;
|
2020-07-25 03:14:29 +02:00
|
|
|
import androidx.appcompat.widget.Toolbar;
|
2019-12-29 22:15:01 +01:00
|
|
|
import androidx.coordinatorlayout.widget.CoordinatorLayout;
|
2020-08-16 10:24:58 +02:00
|
|
|
import androidx.core.content.ContextCompat;
|
2020-10-31 21:55:45 +01:00
|
|
|
import androidx.core.text.HtmlCompat;
|
2020-08-16 10:24:58 +02:00
|
|
|
import androidx.fragment.app.Fragment;
|
2020-10-31 21:55:45 +01:00
|
|
|
import androidx.preference.PreferenceManager;
|
2020-08-16 10:24:58 +02:00
|
|
|
import androidx.viewpager.widget.ViewPager;
|
|
|
|
|
2019-12-29 22:15:01 +01:00
|
|
|
import com.google.android.exoplayer2.ExoPlaybackException;
|
|
|
|
import com.google.android.exoplayer2.PlaybackParameters;
|
2019-10-04 14:59:08 +02:00
|
|
|
import com.google.android.material.appbar.AppBarLayout;
|
2019-12-29 22:15:01 +01:00
|
|
|
import com.google.android.material.bottomsheet.BottomSheetBehavior;
|
2019-10-04 14:59:08 +02:00
|
|
|
import com.google.android.material.tabs.TabLayout;
|
2017-03-31 20:15:26 +02:00
|
|
|
import com.nostra13.universalimageloader.core.assist.FailReason;
|
2018-03-23 02:11:59 +01:00
|
|
|
import com.nostra13.universalimageloader.core.listener.ImageLoadingListener;
|
2017-03-31 20:15:26 +02:00
|
|
|
import com.nostra13.universalimageloader.core.listener.SimpleImageLoadingListener;
|
|
|
|
|
2020-09-17 22:42:35 +02:00
|
|
|
import org.schabi.newpipe.App;
|
2016-08-02 21:17:54 +02:00
|
|
|
import org.schabi.newpipe.R;
|
2017-03-31 20:15:26 +02:00
|
|
|
import org.schabi.newpipe.ReCaptchaActivity;
|
|
|
|
import org.schabi.newpipe.download.DownloadDialog;
|
2017-06-17 13:43:09 +02:00
|
|
|
import org.schabi.newpipe.extractor.InfoItem;
|
2017-03-31 20:15:26 +02:00
|
|
|
import org.schabi.newpipe.extractor.NewPipe;
|
2018-12-23 22:07:27 +01:00
|
|
|
import org.schabi.newpipe.extractor.ServiceList;
|
2018-09-23 03:32:19 +02:00
|
|
|
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
|
2018-07-08 17:46:21 +02:00
|
|
|
import org.schabi.newpipe.extractor.services.youtube.extractors.YoutubeStreamExtractor;
|
2017-09-03 08:04:18 +02:00
|
|
|
import org.schabi.newpipe.extractor.stream.AudioStream;
|
2020-02-06 23:54:36 +01:00
|
|
|
import org.schabi.newpipe.extractor.stream.Description;
|
2018-06-19 03:27:30 +02:00
|
|
|
import org.schabi.newpipe.extractor.stream.Stream;
|
2017-09-03 08:04:18 +02:00
|
|
|
import org.schabi.newpipe.extractor.stream.StreamInfo;
|
2018-02-26 00:10:11 +01:00
|
|
|
import org.schabi.newpipe.extractor.stream.StreamType;
|
2017-09-03 08:04:18 +02:00
|
|
|
import org.schabi.newpipe.extractor.stream.VideoStream;
|
|
|
|
import org.schabi.newpipe.fragments.BackPressable;
|
|
|
|
import org.schabi.newpipe.fragments.BaseStateFragment;
|
2019-03-03 13:50:15 +01:00
|
|
|
import org.schabi.newpipe.fragments.EmptyFragment;
|
2018-10-02 17:09:16 +02:00
|
|
|
import org.schabi.newpipe.fragments.list.comments.CommentsFragment;
|
|
|
|
import org.schabi.newpipe.fragments.list.videos.RelatedVideosFragment;
|
2018-09-03 01:22:59 +02:00
|
|
|
import org.schabi.newpipe.local.dialog.PlaylistAppendDialog;
|
2020-09-29 00:32:24 +02:00
|
|
|
import org.schabi.newpipe.local.dialog.PlaylistCreationDialog;
|
2018-09-03 01:22:59 +02:00
|
|
|
import org.schabi.newpipe.local.history.HistoryRecordManager;
|
2021-01-08 18:35:33 +01:00
|
|
|
import org.schabi.newpipe.player.Player;
|
2020-07-14 19:21:32 +02:00
|
|
|
import org.schabi.newpipe.player.MainPlayer;
|
2020-07-13 03:17:21 +02:00
|
|
|
import org.schabi.newpipe.player.event.OnKeyDownListener;
|
2020-09-17 22:42:35 +02:00
|
|
|
import org.schabi.newpipe.player.event.PlayerServiceExtendedEventListener;
|
2019-12-29 22:15:01 +01:00
|
|
|
import org.schabi.newpipe.player.helper.PlayerHelper;
|
2020-09-17 22:42:35 +02:00
|
|
|
import org.schabi.newpipe.player.helper.PlayerHolder;
|
2020-07-14 19:21:32 +02:00
|
|
|
import org.schabi.newpipe.player.playqueue.PlayQueue;
|
|
|
|
import org.schabi.newpipe.player.playqueue.PlayQueueItem;
|
|
|
|
import org.schabi.newpipe.player.playqueue.SinglePlayQueue;
|
2018-09-03 01:22:59 +02:00
|
|
|
import org.schabi.newpipe.report.ErrorActivity;
|
2020-10-04 03:50:28 +02:00
|
|
|
import org.schabi.newpipe.report.ErrorInfo;
|
2017-06-28 07:27:32 +02:00
|
|
|
import org.schabi.newpipe.report.UserAction;
|
2017-10-08 21:04:37 +02:00
|
|
|
import org.schabi.newpipe.util.Constants;
|
2020-08-16 10:24:58 +02:00
|
|
|
import org.schabi.newpipe.util.DeviceUtils;
|
2017-09-03 08:04:18 +02:00
|
|
|
import org.schabi.newpipe.util.ExtractorHelper;
|
2018-03-16 04:07:20 +01:00
|
|
|
import org.schabi.newpipe.util.ImageDisplayConstants;
|
2017-09-03 08:04:18 +02:00
|
|
|
import org.schabi.newpipe.util.ListHelper;
|
2017-05-08 15:33:26 +02:00
|
|
|
import org.schabi.newpipe.util.Localization;
|
2017-04-09 19:34:00 +02:00
|
|
|
import org.schabi.newpipe.util.NavigationHelper;
|
2017-03-31 20:15:26 +02:00
|
|
|
import org.schabi.newpipe.util.PermissionHelper;
|
2019-04-06 20:17:04 +02:00
|
|
|
import org.schabi.newpipe.util.ShareUtils;
|
2020-03-25 16:23:47 +01:00
|
|
|
import org.schabi.newpipe.util.ThemeHelper;
|
2019-04-13 09:31:32 +02:00
|
|
|
import org.schabi.newpipe.views.AnimatedProgressBar;
|
2019-11-14 14:38:16 +01:00
|
|
|
import org.schabi.newpipe.views.LargeTextMovementMethod;
|
2015-11-17 00:32:00 +01:00
|
|
|
|
2020-07-14 19:21:32 +02:00
|
|
|
import java.util.Iterator;
|
|
|
|
import java.util.LinkedList;
|
|
|
|
import java.util.List;
|
2020-10-18 20:19:50 +02:00
|
|
|
import java.util.Objects;
|
2019-04-13 09:31:32 +02:00
|
|
|
import java.util.concurrent.TimeUnit;
|
2017-09-03 08:04:18 +02:00
|
|
|
|
|
|
|
import icepick.State;
|
2020-02-08 09:56:37 +01:00
|
|
|
import io.noties.markwon.Markwon;
|
|
|
|
import io.noties.markwon.linkify.LinkifyPlugin;
|
2020-10-31 21:55:45 +01:00
|
|
|
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;
|
2017-04-09 19:34:00 +02:00
|
|
|
|
2020-12-15 17:41:21 +01:00
|
|
|
import static android.text.TextUtils.isEmpty;
|
2019-02-15 20:53:26 +01:00
|
|
|
import static org.schabi.newpipe.extractor.StreamingService.ServiceInfo.MediaCapability.COMMENTS;
|
2020-08-16 10:24:58 +02:00
|
|
|
import static org.schabi.newpipe.extractor.stream.StreamExtractor.NO_AGE_LIMIT;
|
2020-09-27 03:11:38 +02:00
|
|
|
import static org.schabi.newpipe.player.helper.PlayerHelper.globalScreenOrientationLocked;
|
2020-03-10 10:06:38 +01:00
|
|
|
import static org.schabi.newpipe.player.helper.PlayerHelper.isClearingQueueConfirmationRequired;
|
2019-12-29 22:15:01 +01:00
|
|
|
import static org.schabi.newpipe.player.playqueue.PlayQueueItem.RECOVERY_UNSET;
|
2017-05-08 15:33:26 +02:00
|
|
|
import static org.schabi.newpipe.util.AnimationUtils.animateView;
|
2020-12-20 15:05:37 +01:00
|
|
|
import static org.schabi.newpipe.util.ExtractorHelper.showMetaInfoInTextView;
|
2017-05-08 15:33:26 +02:00
|
|
|
|
2020-10-18 20:19:50 +02:00
|
|
|
public final class VideoDetailFragment
|
2018-02-16 11:31:25 +01:00
|
|
|
extends BaseStateFragment<StreamInfo>
|
|
|
|
implements BackPressable,
|
|
|
|
SharedPreferences.OnSharedPreferenceChangeListener,
|
|
|
|
View.OnClickListener,
|
2019-12-29 22:15:01 +01:00
|
|
|
View.OnLongClickListener,
|
2020-09-17 22:42:35 +02:00
|
|
|
PlayerServiceExtendedEventListener,
|
2020-07-13 03:17:21 +02:00
|
|
|
OnKeyDownListener {
|
2020-10-18 20:19:50 +02:00
|
|
|
public static final String KEY_SWITCHING_PLAYERS = "switching_players";
|
2017-03-31 20:15:26 +02:00
|
|
|
|
2017-04-12 08:07:15 +02:00
|
|
|
private static final int RELATED_STREAMS_UPDATE_FLAG = 0x1;
|
2020-06-27 05:25:50 +02:00
|
|
|
private static final int COMMENTS_UPDATE_FLAG = 0x2;
|
2019-12-29 22:15:01 +01:00
|
|
|
private static final float MAX_OVERLAY_ALPHA = 0.9f;
|
2020-02-05 06:59:30 +01:00
|
|
|
private static final float MAX_PLAYER_HEIGHT = 0.7f;
|
2019-12-29 22:15:01 +01:00
|
|
|
|
2020-07-14 19:21:32 +02:00
|
|
|
public static final String ACTION_SHOW_MAIN_PLAYER =
|
2020-12-19 14:48:03 +01:00
|
|
|
App.PACKAGE_NAME + ".VideoDetailFragment.ACTION_SHOW_MAIN_PLAYER";
|
2020-07-14 19:21:32 +02:00
|
|
|
public static final String ACTION_HIDE_MAIN_PLAYER =
|
2020-12-19 14:48:03 +01:00
|
|
|
App.PACKAGE_NAME + ".VideoDetailFragment.ACTION_HIDE_MAIN_PLAYER";
|
2020-09-29 05:22:53 +02:00
|
|
|
public static final String ACTION_PLAYER_STARTED =
|
2020-12-19 14:48:03 +01:00
|
|
|
App.PACKAGE_NAME + ".VideoDetailFragment.ACTION_PLAYER_STARTED";
|
2020-07-14 19:21:32 +02:00
|
|
|
public static final String ACTION_VIDEO_FRAGMENT_RESUMED =
|
2020-12-19 14:48:03 +01:00
|
|
|
App.PACKAGE_NAME + ".VideoDetailFragment.ACTION_VIDEO_FRAGMENT_RESUMED";
|
2020-07-14 19:21:32 +02:00
|
|
|
public static final String ACTION_VIDEO_FRAGMENT_STOPPED =
|
2020-12-19 14:48:03 +01:00
|
|
|
App.PACKAGE_NAME + ".VideoDetailFragment.ACTION_VIDEO_FRAGMENT_STOPPED";
|
2017-03-31 20:15:26 +02:00
|
|
|
|
2020-06-27 05:25:50 +02:00
|
|
|
private static final String COMMENTS_TAB_TAG = "COMMENTS";
|
|
|
|
private static final String RELATED_TAB_TAG = "NEXT VIDEO";
|
|
|
|
private static final String EMPTY_TAB_TAG = "EMPTY TAB";
|
|
|
|
|
2017-03-31 20:15:26 +02:00
|
|
|
private boolean showRelatedStreams;
|
2018-09-03 01:22:59 +02:00
|
|
|
private boolean showComments;
|
2019-03-24 02:01:28 +01:00
|
|
|
private String selectedTabTag;
|
2017-03-31 20:15:26 +02:00
|
|
|
|
2020-06-27 05:25:50 +02:00
|
|
|
private int updateFlags = 0;
|
|
|
|
|
2018-09-03 01:22:59 +02:00
|
|
|
@State
|
|
|
|
protected int serviceId = Constants.NO_SERVICE_ID;
|
|
|
|
@State
|
2020-10-18 20:19:50 +02:00
|
|
|
@NonNull
|
|
|
|
protected String title = "";
|
2018-09-03 01:22:59 +02:00
|
|
|
@State
|
2020-10-18 20:19:50 +02:00
|
|
|
@Nullable
|
|
|
|
protected String url = null;
|
|
|
|
@Nullable
|
|
|
|
protected PlayQueue playQueue = null;
|
2019-12-29 22:15:01 +01:00
|
|
|
@State
|
2020-01-06 11:39:01 +01:00
|
|
|
int bottomSheetState = BottomSheetBehavior.STATE_EXPANDED;
|
2020-01-13 17:24:28 +01:00
|
|
|
@State
|
|
|
|
protected boolean autoPlayEnabled = true;
|
2017-09-03 08:04:18 +02:00
|
|
|
|
2020-10-18 20:19:50 +02:00
|
|
|
@Nullable
|
|
|
|
private StreamInfo currentInfo = null;
|
2017-09-03 08:04:18 +02:00
|
|
|
private Disposable currentWorker;
|
2018-09-03 01:22:59 +02:00
|
|
|
@NonNull
|
2020-10-18 20:19:50 +02:00
|
|
|
private final CompositeDisposable disposables = new CompositeDisposable();
|
2019-04-13 09:31:32 +02:00
|
|
|
@Nullable
|
|
|
|
private Disposable positionSubscriber = null;
|
2017-06-28 03:39:33 +02:00
|
|
|
|
2018-04-08 13:08:19 +02:00
|
|
|
private List<VideoStream> sortedVideoStreams;
|
|
|
|
private int selectedVideoStreamIndex = -1;
|
2020-07-12 02:59:47 +02:00
|
|
|
private BottomSheetBehavior<FrameLayout> bottomSheetBehavior;
|
2019-12-29 22:15:01 +01:00
|
|
|
private BroadcastReceiver broadcastReceiver;
|
2018-02-16 12:18:15 +01:00
|
|
|
|
2017-03-31 20:15:26 +02:00
|
|
|
/*//////////////////////////////////////////////////////////////////////////
|
|
|
|
// Views
|
|
|
|
//////////////////////////////////////////////////////////////////////////*/
|
2018-03-10 17:16:51 +01:00
|
|
|
|
2017-06-15 16:26:48 +02:00
|
|
|
private LinearLayout contentRootLayoutHiding;
|
2017-03-31 20:15:26 +02:00
|
|
|
|
2017-06-15 16:26:48 +02:00
|
|
|
private View thumbnailBackgroundButton;
|
2017-03-31 20:15:26 +02:00
|
|
|
private ImageView thumbnailImageView;
|
|
|
|
private ImageView thumbnailPlayButton;
|
2019-04-13 09:31:32 +02:00
|
|
|
private AnimatedProgressBar positionView;
|
2020-08-05 11:46:25 +02:00
|
|
|
private ViewGroup playerPlaceholder;
|
2015-09-04 02:15:03 +02:00
|
|
|
|
2017-03-31 20:15:26 +02:00
|
|
|
private View videoTitleRoot;
|
|
|
|
private TextView videoTitleTextView;
|
|
|
|
private ImageView videoTitleToggleArrow;
|
|
|
|
private TextView videoCountView;
|
|
|
|
|
2017-04-26 21:32:04 +02:00
|
|
|
private TextView detailControlsBackground;
|
|
|
|
private TextView detailControlsPopup;
|
2018-01-17 23:32:09 +01:00
|
|
|
private TextView detailControlsAddToPlaylist;
|
2018-02-11 21:34:32 +01:00
|
|
|
private TextView detailControlsDownload;
|
2017-10-14 23:09:49 +02:00
|
|
|
private TextView appendControlsDetail;
|
2018-03-10 17:16:51 +01:00
|
|
|
private TextView detailDurationView;
|
2019-04-13 09:31:32 +02:00
|
|
|
private TextView detailPositionView;
|
2017-04-26 21:32:04 +02:00
|
|
|
|
2020-12-20 15:05:37 +01:00
|
|
|
private View detailMetaInfoSeparator;
|
|
|
|
private TextView detailMetaInfoTextView;
|
2020-12-15 17:41:21 +01:00
|
|
|
|
2017-06-15 16:26:48 +02:00
|
|
|
private LinearLayout videoDescriptionRootLayout;
|
2017-03-31 20:15:26 +02:00
|
|
|
private TextView videoUploadDateView;
|
|
|
|
private TextView videoDescriptionView;
|
|
|
|
|
2017-04-28 05:58:50 +02:00
|
|
|
private View uploaderRootLayout;
|
2017-03-31 20:15:26 +02:00
|
|
|
private TextView uploaderTextView;
|
|
|
|
private ImageView uploaderThumb;
|
2020-04-16 17:35:42 +02:00
|
|
|
private TextView subChannelTextView;
|
|
|
|
private ImageView subChannelThumb;
|
2017-03-31 20:15:26 +02:00
|
|
|
|
|
|
|
private TextView thumbsUpTextView;
|
|
|
|
private ImageView thumbsUpImageView;
|
|
|
|
private TextView thumbsDownTextView;
|
|
|
|
private ImageView thumbsDownImageView;
|
|
|
|
private TextView thumbsDisabledTextView;
|
|
|
|
|
2019-12-29 22:15:01 +01:00
|
|
|
private RelativeLayout overlay;
|
|
|
|
private LinearLayout overlayMetadata;
|
|
|
|
private ImageView overlayThumbnailImageView;
|
|
|
|
private TextView overlayTitleTextView;
|
|
|
|
private TextView overlayChannelTextView;
|
|
|
|
private LinearLayout overlayButtons;
|
|
|
|
private ImageButton overlayPlayPauseButton;
|
|
|
|
private ImageButton overlayCloseButton;
|
|
|
|
|
2018-10-02 17:09:16 +02:00
|
|
|
private AppBarLayout appBarLayout;
|
2020-07-12 02:59:47 +02:00
|
|
|
private ViewPager viewPager;
|
2020-09-06 14:01:59 +02:00
|
|
|
private TabAdapter pageAdapter;
|
2018-10-02 17:09:16 +02:00
|
|
|
private TabLayout tabLayout;
|
2018-12-08 22:51:55 +01:00
|
|
|
private FrameLayout relatedStreamsLayout;
|
2018-09-03 01:22:59 +02:00
|
|
|
|
2020-01-16 12:20:22 +01:00
|
|
|
private ContentObserver settingsContentObserver;
|
2019-12-29 22:15:01 +01:00
|
|
|
private MainPlayer playerService;
|
2021-01-08 18:35:33 +01:00
|
|
|
private Player player;
|
2019-12-29 22:15:01 +01:00
|
|
|
|
|
|
|
|
|
|
|
/*//////////////////////////////////////////////////////////////////////////
|
|
|
|
// Service management
|
|
|
|
//////////////////////////////////////////////////////////////////////////*/
|
2020-09-17 22:42:35 +02:00
|
|
|
@Override
|
2021-01-08 18:35:33 +01:00
|
|
|
public void onServiceConnected(final Player connectedPlayer,
|
2020-09-17 22:42:35 +02:00
|
|
|
final MainPlayer connectedPlayerService,
|
|
|
|
final boolean playAfterConnect) {
|
|
|
|
player = connectedPlayer;
|
|
|
|
playerService = connectedPlayerService;
|
2019-12-29 22:15:01 +01:00
|
|
|
|
2020-09-17 22:42:35 +02:00
|
|
|
// It will do nothing if the player is not in fullscreen mode
|
|
|
|
hideSystemUiIfNeeded();
|
2019-12-29 22:15:01 +01:00
|
|
|
|
2020-09-17 22:42:35 +02:00
|
|
|
if (!player.videoPlayerSelected() && !playAfterConnect) {
|
|
|
|
return;
|
2020-07-14 19:21:32 +02:00
|
|
|
}
|
2019-12-29 22:15:01 +01:00
|
|
|
|
2020-09-17 22:42:35 +02:00
|
|
|
if (isLandscape()) {
|
|
|
|
// If the video is playing but orientation changed
|
|
|
|
// let's make the video in fullscreen again
|
|
|
|
checkLandscape();
|
2020-11-20 21:43:05 +01:00
|
|
|
} else if (player.isFullscreen() && !player.isVerticalVideo()
|
|
|
|
// Tablet UI has orientation-independent fullscreen
|
|
|
|
&& !DeviceUtils.isTablet(activity)) {
|
2020-09-17 22:42:35 +02:00
|
|
|
// Device is in portrait orientation after rotation but UI is in fullscreen.
|
|
|
|
// Return back to non-fullscreen state
|
|
|
|
player.toggleFullscreen();
|
2019-12-29 22:15:01 +01:00
|
|
|
}
|
|
|
|
|
2020-09-17 22:42:35 +02:00
|
|
|
if (playerIsNotStopped() && player.videoPlayerSelected()) {
|
|
|
|
addVideoPlayerView();
|
2020-07-14 19:21:32 +02:00
|
|
|
}
|
2019-12-29 22:15:01 +01:00
|
|
|
|
2020-09-17 22:42:35 +02:00
|
|
|
if (playAfterConnect
|
|
|
|
|| (currentInfo != null
|
|
|
|
&& isAutoplayEnabled()
|
|
|
|
&& player.getParentActivity() == null)) {
|
2020-11-01 21:25:31 +01:00
|
|
|
autoPlayEnabled = true; // forcefully start playing
|
2020-09-17 22:42:35 +02:00
|
|
|
openVideoPlayer();
|
2020-07-14 19:21:32 +02:00
|
|
|
}
|
2019-12-29 22:15:01 +01:00
|
|
|
}
|
|
|
|
|
2020-09-17 22:42:35 +02:00
|
|
|
@Override
|
|
|
|
public void onServiceDisconnected() {
|
|
|
|
playerService = null;
|
|
|
|
player = null;
|
|
|
|
restoreDefaultBrightness();
|
2019-12-29 22:15:01 +01:00
|
|
|
}
|
|
|
|
|
2018-02-16 12:18:15 +01:00
|
|
|
|
2017-04-09 19:34:00 +02:00
|
|
|
/*////////////////////////////////////////////////////////////////////////*/
|
|
|
|
|
2020-10-18 20:19:50 +02:00
|
|
|
public static VideoDetailFragment getInstance(final int serviceId,
|
|
|
|
@Nullable final String videoUrl,
|
|
|
|
@NonNull final String name,
|
|
|
|
@Nullable final PlayQueue queue) {
|
2020-08-16 10:24:58 +02:00
|
|
|
final VideoDetailFragment instance = new VideoDetailFragment();
|
2020-09-17 22:42:35 +02:00
|
|
|
instance.setInitialData(serviceId, videoUrl, name, queue);
|
2017-04-09 19:34:00 +02:00
|
|
|
return instance;
|
|
|
|
}
|
|
|
|
|
2020-09-29 23:49:34 +02:00
|
|
|
public static VideoDetailFragment getInstanceInCollapsedState() {
|
2020-09-29 05:22:53 +02:00
|
|
|
final VideoDetailFragment instance = new VideoDetailFragment();
|
|
|
|
instance.bottomSheetState = BottomSheetBehavior.STATE_COLLAPSED;
|
|
|
|
return instance;
|
|
|
|
}
|
|
|
|
|
2020-04-02 13:51:10 +02:00
|
|
|
|
2017-03-31 20:15:26 +02:00
|
|
|
/*//////////////////////////////////////////////////////////////////////////
|
2017-04-09 19:34:00 +02:00
|
|
|
// Fragment's Lifecycle
|
2017-03-31 20:15:26 +02:00
|
|
|
//////////////////////////////////////////////////////////////////////////*/
|
|
|
|
|
|
|
|
@Override
|
2020-03-31 19:20:15 +02:00
|
|
|
public void onCreate(final Bundle savedInstanceState) {
|
2015-09-04 02:15:03 +02:00
|
|
|
super.onCreate(savedInstanceState);
|
2019-12-29 22:15:01 +01:00
|
|
|
|
2018-02-16 11:31:25 +01:00
|
|
|
showRelatedStreams = PreferenceManager.getDefaultSharedPreferences(activity)
|
|
|
|
.getBoolean(getString(R.string.show_next_video_key), true);
|
2018-09-03 01:22:59 +02:00
|
|
|
|
|
|
|
showComments = PreferenceManager.getDefaultSharedPreferences(activity)
|
2018-10-02 17:26:14 +02:00
|
|
|
.getBoolean(getString(R.string.show_comments_key), true);
|
2018-09-03 01:22:59 +02:00
|
|
|
|
2019-03-24 02:01:28 +01:00
|
|
|
selectedTabTag = PreferenceManager.getDefaultSharedPreferences(activity)
|
|
|
|
.getString(getString(R.string.stream_info_selected_tab_key), COMMENTS_TAB_TAG);
|
|
|
|
|
2018-02-16 11:31:25 +01:00
|
|
|
PreferenceManager.getDefaultSharedPreferences(activity)
|
|
|
|
.registerOnSharedPreferenceChangeListener(this);
|
2019-12-29 22:15:01 +01:00
|
|
|
|
|
|
|
setupBroadcastReceiver();
|
2020-01-08 17:16:50 +01:00
|
|
|
|
2020-01-16 12:20:22 +01:00
|
|
|
settingsContentObserver = new ContentObserver(new Handler()) {
|
|
|
|
@Override
|
2020-07-12 02:59:47 +02:00
|
|
|
public void onChange(final boolean selfChange) {
|
2020-09-27 03:11:38 +02:00
|
|
|
if (activity != null && !globalScreenOrientationLocked(activity)) {
|
2020-01-16 12:20:22 +01:00
|
|
|
activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
|
2020-07-14 19:21:32 +02:00
|
|
|
}
|
2020-01-16 12:20:22 +01:00
|
|
|
}
|
|
|
|
};
|
2020-01-08 17:16:50 +01:00
|
|
|
activity.getContentResolver().registerContentObserver(
|
2020-01-16 12:20:22 +01:00
|
|
|
Settings.System.getUriFor(Settings.System.ACCELEROMETER_ROTATION), false,
|
2020-01-08 17:16:50 +01:00
|
|
|
settingsContentObserver);
|
2017-04-09 19:34:00 +02:00
|
|
|
}
|
2015-09-04 02:15:03 +02:00
|
|
|
|
2017-04-09 19:34:00 +02:00
|
|
|
@Override
|
2020-03-31 19:20:15 +02:00
|
|
|
public View onCreateView(@NonNull final LayoutInflater inflater, final ViewGroup container,
|
|
|
|
final Bundle savedInstanceState) {
|
2017-04-09 19:34:00 +02:00
|
|
|
return inflater.inflate(R.layout.fragment_video_detail, container, false);
|
|
|
|
}
|
2017-03-31 20:15:26 +02:00
|
|
|
|
2017-04-09 19:34:00 +02:00
|
|
|
@Override
|
2017-09-03 08:04:18 +02:00
|
|
|
public void onPause() {
|
|
|
|
super.onPause();
|
2020-03-31 19:20:15 +02:00
|
|
|
if (currentWorker != null) {
|
|
|
|
currentWorker.dispose();
|
|
|
|
}
|
2020-09-11 19:52:38 +02:00
|
|
|
restoreDefaultBrightness();
|
2020-08-27 22:55:57 +02:00
|
|
|
PreferenceManager.getDefaultSharedPreferences(requireContext())
|
2019-03-24 02:01:28 +01:00
|
|
|
.edit()
|
2020-03-31 19:20:15 +02:00
|
|
|
.putString(getString(R.string.stream_info_selected_tab_key),
|
|
|
|
pageAdapter.getItemTitle(viewPager.getCurrentItem()))
|
2019-03-24 02:01:28 +01:00
|
|
|
.apply();
|
2017-08-12 06:50:25 +02:00
|
|
|
}
|
|
|
|
|
2017-04-26 21:32:04 +02:00
|
|
|
@Override
|
|
|
|
public void onResume() {
|
|
|
|
super.onResume();
|
|
|
|
|
2020-02-29 00:57:54 +01:00
|
|
|
activity.sendBroadcast(new Intent(ACTION_VIDEO_FRAGMENT_RESUMED));
|
2019-12-29 22:15:01 +01:00
|
|
|
|
2020-09-04 04:39:55 +02:00
|
|
|
setupBrightness();
|
2019-12-29 22:15:01 +01:00
|
|
|
|
2017-04-26 21:32:04 +02:00
|
|
|
if (updateFlags != 0) {
|
2017-09-03 08:04:18 +02:00
|
|
|
if (!isLoading.get() && currentInfo != null) {
|
2020-07-14 19:21:32 +02:00
|
|
|
if ((updateFlags & RELATED_STREAMS_UPDATE_FLAG) != 0) {
|
|
|
|
startLoading(false);
|
|
|
|
}
|
|
|
|
if ((updateFlags & COMMENTS_UPDATE_FLAG) != 0) {
|
|
|
|
startLoading(false);
|
|
|
|
}
|
2017-04-26 21:32:04 +02:00
|
|
|
}
|
2017-05-09 03:23:27 +02:00
|
|
|
|
2017-04-26 21:32:04 +02:00
|
|
|
updateFlags = 0;
|
|
|
|
}
|
|
|
|
|
2020-01-15 19:32:29 +01:00
|
|
|
// Check if it was loading when the fragment was stopped/paused
|
2020-07-14 19:21:32 +02:00
|
|
|
if (wasLoading.getAndSet(false) && !wasCleared()) {
|
2020-03-10 10:06:38 +01:00
|
|
|
startLoading(false);
|
2020-07-14 19:21:32 +02:00
|
|
|
}
|
2019-12-29 22:15:01 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onStop() {
|
|
|
|
super.onStop();
|
|
|
|
|
2020-07-14 19:21:32 +02:00
|
|
|
if (!activity.isChangingConfigurations()) {
|
2020-02-29 00:57:54 +01:00
|
|
|
activity.sendBroadcast(new Intent(ACTION_VIDEO_FRAGMENT_STOPPED));
|
2020-07-14 19:21:32 +02:00
|
|
|
}
|
2017-04-26 21:32:04 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onDestroy() {
|
|
|
|
super.onDestroy();
|
2019-12-29 22:15:01 +01:00
|
|
|
|
2020-07-14 19:21:32 +02:00
|
|
|
// Stop the service when user leaves the app with double back press
|
|
|
|
// if video player is selected. Otherwise unbind
|
|
|
|
if (activity.isFinishing() && player != null && player.videoPlayerSelected()) {
|
2020-09-17 22:42:35 +02:00
|
|
|
PlayerHolder.stopService(App.getApp());
|
2020-07-14 19:21:32 +02:00
|
|
|
} else {
|
2020-09-17 22:42:35 +02:00
|
|
|
PlayerHolder.removeListener();
|
2020-07-14 19:21:32 +02:00
|
|
|
}
|
2019-12-29 22:15:01 +01:00
|
|
|
|
2018-02-16 11:31:25 +01:00
|
|
|
PreferenceManager.getDefaultSharedPreferences(activity)
|
|
|
|
.unregisterOnSharedPreferenceChangeListener(this);
|
2020-01-08 17:16:50 +01:00
|
|
|
activity.unregisterReceiver(broadcastReceiver);
|
|
|
|
activity.getContentResolver().unregisterContentObserver(settingsContentObserver);
|
2017-09-03 08:04:18 +02:00
|
|
|
|
2020-03-31 19:20:15 +02:00
|
|
|
if (positionSubscriber != null) {
|
|
|
|
positionSubscriber.dispose();
|
|
|
|
}
|
|
|
|
if (currentWorker != null) {
|
|
|
|
currentWorker.dispose();
|
|
|
|
}
|
2020-07-12 02:59:47 +02:00
|
|
|
disposables.clear();
|
2019-04-13 09:31:32 +02:00
|
|
|
positionSubscriber = null;
|
2017-09-03 08:04:18 +02:00
|
|
|
currentWorker = null;
|
2020-01-17 15:37:53 +01:00
|
|
|
bottomSheetBehavior.setBottomSheetCallback(null);
|
2020-09-17 22:42:35 +02:00
|
|
|
|
|
|
|
if (activity.isFinishing()) {
|
|
|
|
playQueue = null;
|
|
|
|
currentInfo = null;
|
|
|
|
stack = new LinkedList<>();
|
|
|
|
}
|
2017-03-31 20:15:26 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2020-03-31 19:20:15 +02:00
|
|
|
public void onActivityResult(final int requestCode, final int resultCode, final Intent data) {
|
2017-03-31 20:15:26 +02:00
|
|
|
super.onActivityResult(requestCode, resultCode, data);
|
|
|
|
switch (requestCode) {
|
|
|
|
case ReCaptchaActivity.RECAPTCHA_REQUEST:
|
2017-04-09 19:34:00 +02:00
|
|
|
if (resultCode == Activity.RESULT_OK) {
|
2020-10-18 20:19:50 +02:00
|
|
|
NavigationHelper.openVideoDetailFragment(requireContext(), getFM(),
|
|
|
|
serviceId, url, title, null, false);
|
2020-03-31 19:20:15 +02:00
|
|
|
} else {
|
|
|
|
Log.e(TAG, "ReCaptcha failed");
|
|
|
|
}
|
2017-03-31 20:15:26 +02:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
Log.e(TAG, "Request code from activity not supported [" + requestCode + "]");
|
|
|
|
break;
|
|
|
|
}
|
2015-10-29 17:56:35 +01:00
|
|
|
}
|
|
|
|
|
2016-01-01 23:04:29 +01:00
|
|
|
@Override
|
2020-03-31 19:20:15 +02:00
|
|
|
public void onSharedPreferenceChanged(final SharedPreferences sharedPreferences,
|
|
|
|
final String key) {
|
2017-03-31 20:15:26 +02:00
|
|
|
if (key.equals(getString(R.string.show_next_video_key))) {
|
|
|
|
showRelatedStreams = sharedPreferences.getBoolean(key, true);
|
2017-04-12 08:07:15 +02:00
|
|
|
updateFlags |= RELATED_STREAMS_UPDATE_FLAG;
|
2018-10-02 17:26:14 +02:00
|
|
|
} else if (key.equals(getString(R.string.show_comments_key))) {
|
2018-09-03 01:22:59 +02:00
|
|
|
showComments = sharedPreferences.getBoolean(key, true);
|
|
|
|
updateFlags |= COMMENTS_UPDATE_FLAG;
|
2017-03-31 20:15:26 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-04-26 21:32:04 +02:00
|
|
|
/*//////////////////////////////////////////////////////////////////////////
|
|
|
|
// OnClick
|
|
|
|
//////////////////////////////////////////////////////////////////////////*/
|
|
|
|
|
|
|
|
@Override
|
2020-03-31 19:20:15 +02:00
|
|
|
public void onClick(final View v) {
|
2017-04-26 21:32:04 +02:00
|
|
|
switch (v.getId()) {
|
|
|
|
case R.id.detail_controls_background:
|
2017-10-13 02:02:07 +02:00
|
|
|
openBackgroundPlayer(false);
|
2017-04-26 21:32:04 +02:00
|
|
|
break;
|
|
|
|
case R.id.detail_controls_popup:
|
2017-10-13 02:02:07 +02:00
|
|
|
openPopupPlayer(false);
|
2017-04-26 21:32:04 +02:00
|
|
|
break;
|
2018-01-17 23:32:09 +01:00
|
|
|
case R.id.detail_controls_playlist_append:
|
2020-08-03 14:47:02 +02:00
|
|
|
if (getFM() != null && currentInfo != null) {
|
2020-09-29 00:32:24 +02:00
|
|
|
|
|
|
|
final PlaylistAppendDialog d = PlaylistAppendDialog.fromStreamInfo(currentInfo);
|
|
|
|
disposables.add(
|
2020-12-19 14:48:03 +01:00
|
|
|
PlaylistAppendDialog.onPlaylistFound(getContext(),
|
|
|
|
() -> d.show(getFM(), TAG),
|
|
|
|
() -> PlaylistCreationDialog.newInstance(d).show(getFM(), TAG)
|
|
|
|
)
|
2020-09-29 00:32:24 +02:00
|
|
|
);
|
2018-01-17 23:32:09 +01:00
|
|
|
}
|
|
|
|
break;
|
2018-02-11 21:34:32 +01:00
|
|
|
case R.id.detail_controls_download:
|
2019-08-15 04:00:11 +02:00
|
|
|
if (PermissionHelper.checkStoragePermissions(activity,
|
|
|
|
PermissionHelper.DOWNLOAD_DIALOG_REQUEST_CODE)) {
|
|
|
|
this.openDownloadDialog();
|
|
|
|
}
|
2018-02-11 21:34:32 +01:00
|
|
|
break;
|
2017-06-15 16:26:48 +02:00
|
|
|
case R.id.detail_uploader_root_layout:
|
2020-12-15 17:41:21 +01:00
|
|
|
if (isEmpty(currentInfo.getSubChannelUrl())) {
|
|
|
|
if (!isEmpty(currentInfo.getUploaderUrl())) {
|
2020-04-13 22:40:44 +02:00
|
|
|
openChannel(currentInfo.getUploaderUrl(), currentInfo.getUploaderName());
|
2020-03-31 19:20:15 +02:00
|
|
|
}
|
2020-05-08 18:03:19 +02:00
|
|
|
|
|
|
|
if (DEBUG) {
|
|
|
|
Log.i(TAG, "Can't open sub-channel because we got no channel URL");
|
|
|
|
}
|
2020-04-13 22:40:44 +02:00
|
|
|
} else {
|
2020-04-16 17:35:42 +02:00
|
|
|
openChannel(currentInfo.getSubChannelUrl(),
|
|
|
|
currentInfo.getSubChannelName());
|
2017-06-15 16:26:48 +02:00
|
|
|
}
|
2017-04-26 21:32:04 +02:00
|
|
|
break;
|
2017-06-15 16:26:48 +02:00
|
|
|
case R.id.detail_thumbnail_root_layout:
|
2020-11-01 21:25:31 +01:00
|
|
|
autoPlayEnabled = true; // forcefully start playing
|
2020-01-03 17:19:14 +01:00
|
|
|
openVideoPlayer();
|
2017-04-26 21:32:04 +02:00
|
|
|
break;
|
|
|
|
case R.id.detail_title_root_layout:
|
|
|
|
toggleTitleAndDescription();
|
|
|
|
break;
|
2019-12-29 22:15:01 +01:00
|
|
|
case R.id.overlay_thumbnail:
|
|
|
|
case R.id.overlay_metadata_layout:
|
|
|
|
case R.id.overlay_buttons_layout:
|
|
|
|
bottomSheetBehavior.setState(BottomSheetBehavior.STATE_EXPANDED);
|
|
|
|
break;
|
|
|
|
case R.id.overlay_play_pause_button:
|
2020-02-29 00:57:54 +01:00
|
|
|
if (playerIsNotStopped()) {
|
2021-01-08 18:35:33 +01:00
|
|
|
player.playPause();
|
2020-07-12 02:59:47 +02:00
|
|
|
player.hideControls(0, 0);
|
2020-01-03 17:19:14 +01:00
|
|
|
showSystemUi();
|
2020-07-14 19:21:32 +02:00
|
|
|
} else {
|
2020-11-01 21:25:31 +01:00
|
|
|
autoPlayEnabled = true; // forcefully start playing
|
2020-07-14 19:21:32 +02:00
|
|
|
openVideoPlayer();
|
|
|
|
}
|
2019-12-29 22:15:01 +01:00
|
|
|
|
2020-09-29 05:22:53 +02:00
|
|
|
setOverlayPlayPauseImage(player != null && player.isPlaying());
|
2019-12-29 22:15:01 +01:00
|
|
|
break;
|
|
|
|
case R.id.overlay_close_button:
|
|
|
|
bottomSheetBehavior.setState(BottomSheetBehavior.STATE_HIDDEN);
|
|
|
|
break;
|
2017-04-26 21:32:04 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-16 17:35:42 +02:00
|
|
|
private void openChannel(final String subChannelUrl, final String subChannelName) {
|
2020-04-13 22:40:44 +02:00
|
|
|
try {
|
2020-08-03 14:47:02 +02:00
|
|
|
NavigationHelper.openChannelFragment(getFM(), currentInfo.getServiceId(),
|
|
|
|
subChannelUrl, subChannelName);
|
2020-08-16 10:24:58 +02:00
|
|
|
} catch (final Exception e) {
|
2020-04-13 22:40:44 +02:00
|
|
|
ErrorActivity.reportUiError((AppCompatActivity) getActivity(), e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-10-13 02:02:07 +02:00
|
|
|
@Override
|
2020-03-31 19:20:15 +02:00
|
|
|
public boolean onLongClick(final View v) {
|
|
|
|
if (isLoading.get() || currentInfo == null) {
|
|
|
|
return false;
|
|
|
|
}
|
2017-10-13 02:02:07 +02:00
|
|
|
|
|
|
|
switch (v.getId()) {
|
|
|
|
case R.id.detail_controls_background:
|
|
|
|
openBackgroundPlayer(true);
|
|
|
|
break;
|
|
|
|
case R.id.detail_controls_popup:
|
|
|
|
openPopupPlayer(true);
|
|
|
|
break;
|
2018-04-08 21:53:15 +02:00
|
|
|
case R.id.detail_controls_download:
|
2020-01-08 17:16:50 +01:00
|
|
|
NavigationHelper.openDownloads(activity);
|
2018-04-08 21:53:15 +02:00
|
|
|
break;
|
2019-12-29 22:15:01 +01:00
|
|
|
case R.id.overlay_thumbnail:
|
|
|
|
case R.id.overlay_metadata_layout:
|
2020-07-14 19:21:32 +02:00
|
|
|
if (currentInfo != null) {
|
2020-07-13 03:17:21 +02:00
|
|
|
openChannel(currentInfo.getUploaderUrl(), currentInfo.getUploaderName());
|
2020-07-14 19:21:32 +02:00
|
|
|
}
|
2018-04-08 21:53:15 +02:00
|
|
|
break;
|
2020-04-19 23:01:02 +02:00
|
|
|
case R.id.detail_uploader_root_layout:
|
2020-12-15 17:41:21 +01:00
|
|
|
if (isEmpty(currentInfo.getSubChannelUrl())) {
|
2020-04-19 23:01:02 +02:00
|
|
|
Log.w(TAG,
|
|
|
|
"Can't open parent channel because we got no parent channel URL");
|
|
|
|
} else {
|
|
|
|
openChannel(currentInfo.getUploaderUrl(), currentInfo.getUploaderName());
|
|
|
|
}
|
|
|
|
break;
|
2020-06-10 23:11:06 +02:00
|
|
|
case R.id.detail_title_root_layout:
|
2020-08-27 22:56:58 +02:00
|
|
|
ShareUtils.copyToClipboard(requireContext(),
|
|
|
|
videoTitleTextView.getText().toString());
|
2019-12-29 22:15:01 +01:00
|
|
|
break;
|
2017-10-13 02:02:07 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2017-04-26 21:32:04 +02:00
|
|
|
private void toggleTitleAndDescription() {
|
2018-12-08 22:51:55 +01:00
|
|
|
if (videoDescriptionRootLayout.getVisibility() == View.VISIBLE) {
|
|
|
|
videoTitleTextView.setMaxLines(1);
|
|
|
|
videoDescriptionRootLayout.setVisibility(View.GONE);
|
2019-11-14 14:38:16 +01:00
|
|
|
videoDescriptionView.setFocusable(false);
|
2020-03-25 16:23:47 +01:00
|
|
|
videoTitleToggleArrow.setImageResource(
|
|
|
|
ThemeHelper.resolveResourceIdFromAttr(requireContext(), R.attr.ic_expand_more));
|
2018-12-08 22:51:55 +01:00
|
|
|
} else {
|
|
|
|
videoTitleTextView.setMaxLines(10);
|
|
|
|
videoDescriptionRootLayout.setVisibility(View.VISIBLE);
|
2019-11-14 14:38:16 +01:00
|
|
|
videoDescriptionView.setFocusable(true);
|
|
|
|
videoDescriptionView.setMovementMethod(new LargeTextMovementMethod());
|
2020-03-25 16:23:47 +01:00
|
|
|
videoTitleToggleArrow.setImageResource(
|
|
|
|
ThemeHelper.resolveResourceIdFromAttr(requireContext(), R.attr.ic_expand_less));
|
2017-04-26 21:32:04 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-03-31 20:15:26 +02:00
|
|
|
/*//////////////////////////////////////////////////////////////////////////
|
|
|
|
// Init
|
|
|
|
//////////////////////////////////////////////////////////////////////////*/
|
|
|
|
|
2017-09-03 08:04:18 +02:00
|
|
|
@Override
|
2020-03-31 19:20:15 +02:00
|
|
|
protected void initViews(final View rootView, final Bundle savedInstanceState) {
|
2017-04-26 21:32:04 +02:00
|
|
|
super.initViews(rootView, savedInstanceState);
|
2017-06-15 16:26:48 +02:00
|
|
|
thumbnailBackgroundButton = rootView.findViewById(R.id.detail_thumbnail_root_layout);
|
2017-09-03 08:04:18 +02:00
|
|
|
thumbnailImageView = rootView.findViewById(R.id.detail_thumbnail_image_view);
|
|
|
|
thumbnailPlayButton = rootView.findViewById(R.id.detail_thumbnail_play_button);
|
2020-08-05 11:46:25 +02:00
|
|
|
playerPlaceholder = rootView.findViewById(R.id.player_placeholder);
|
2017-03-31 20:15:26 +02:00
|
|
|
|
2017-09-03 08:04:18 +02:00
|
|
|
contentRootLayoutHiding = rootView.findViewById(R.id.detail_content_root_hiding);
|
2017-03-31 20:15:26 +02:00
|
|
|
|
2017-04-09 19:34:00 +02:00
|
|
|
videoTitleRoot = rootView.findViewById(R.id.detail_title_root_layout);
|
2017-09-03 08:04:18 +02:00
|
|
|
videoTitleTextView = rootView.findViewById(R.id.detail_video_title_view);
|
|
|
|
videoTitleToggleArrow = rootView.findViewById(R.id.detail_toggle_description_view);
|
|
|
|
videoCountView = rootView.findViewById(R.id.detail_view_count_view);
|
2019-04-13 09:31:32 +02:00
|
|
|
positionView = rootView.findViewById(R.id.position_view);
|
2017-03-31 20:15:26 +02:00
|
|
|
|
2017-09-03 08:04:18 +02:00
|
|
|
detailControlsBackground = rootView.findViewById(R.id.detail_controls_background);
|
|
|
|
detailControlsPopup = rootView.findViewById(R.id.detail_controls_popup);
|
2018-01-17 23:32:09 +01:00
|
|
|
detailControlsAddToPlaylist = rootView.findViewById(R.id.detail_controls_playlist_append);
|
2018-02-11 21:34:32 +01:00
|
|
|
detailControlsDownload = rootView.findViewById(R.id.detail_controls_download);
|
2017-10-14 23:09:49 +02:00
|
|
|
appendControlsDetail = rootView.findViewById(R.id.touch_append_detail);
|
2018-03-10 17:16:51 +01:00
|
|
|
detailDurationView = rootView.findViewById(R.id.detail_duration_view);
|
2019-04-13 09:31:32 +02:00
|
|
|
detailPositionView = rootView.findViewById(R.id.detail_position_view);
|
2017-04-26 21:32:04 +02:00
|
|
|
|
2020-12-20 15:05:37 +01:00
|
|
|
detailMetaInfoSeparator = rootView.findViewById(R.id.detail_meta_info_separator);
|
|
|
|
detailMetaInfoTextView = rootView.findViewById(R.id.detail_meta_info_text_view);
|
2020-12-15 17:41:21 +01:00
|
|
|
|
2017-09-03 08:04:18 +02:00
|
|
|
videoDescriptionRootLayout = rootView.findViewById(R.id.detail_description_root_layout);
|
|
|
|
videoUploadDateView = rootView.findViewById(R.id.detail_upload_date_view);
|
|
|
|
videoDescriptionView = rootView.findViewById(R.id.detail_description_view);
|
2017-03-31 20:15:26 +02:00
|
|
|
|
2017-09-03 08:04:18 +02:00
|
|
|
thumbsUpTextView = rootView.findViewById(R.id.detail_thumbs_up_count_view);
|
|
|
|
thumbsUpImageView = rootView.findViewById(R.id.detail_thumbs_up_img_view);
|
|
|
|
thumbsDownTextView = rootView.findViewById(R.id.detail_thumbs_down_count_view);
|
|
|
|
thumbsDownImageView = rootView.findViewById(R.id.detail_thumbs_down_img_view);
|
|
|
|
thumbsDisabledTextView = rootView.findViewById(R.id.detail_thumbs_disabled_view);
|
2017-03-31 20:15:26 +02:00
|
|
|
|
2017-04-28 05:58:50 +02:00
|
|
|
uploaderRootLayout = rootView.findViewById(R.id.detail_uploader_root_layout);
|
2017-09-03 08:04:18 +02:00
|
|
|
uploaderTextView = rootView.findViewById(R.id.detail_uploader_text_view);
|
|
|
|
uploaderThumb = rootView.findViewById(R.id.detail_uploader_thumbnail_view);
|
2020-04-16 17:35:42 +02:00
|
|
|
subChannelTextView = rootView.findViewById(R.id.detail_sub_channel_text_view);
|
|
|
|
subChannelThumb = rootView.findViewById(R.id.detail_sub_channel_thumbnail_view);
|
2017-03-31 20:15:26 +02:00
|
|
|
|
2019-12-29 22:15:01 +01:00
|
|
|
overlay = rootView.findViewById(R.id.overlay_layout);
|
|
|
|
overlayMetadata = rootView.findViewById(R.id.overlay_metadata_layout);
|
|
|
|
overlayThumbnailImageView = rootView.findViewById(R.id.overlay_thumbnail);
|
|
|
|
overlayTitleTextView = rootView.findViewById(R.id.overlay_title_text_view);
|
|
|
|
overlayChannelTextView = rootView.findViewById(R.id.overlay_channel_text_view);
|
|
|
|
overlayButtons = rootView.findViewById(R.id.overlay_buttons_layout);
|
|
|
|
overlayPlayPauseButton = rootView.findViewById(R.id.overlay_play_pause_button);
|
|
|
|
overlayCloseButton = rootView.findViewById(R.id.overlay_close_button);
|
|
|
|
|
2018-10-02 17:09:16 +02:00
|
|
|
appBarLayout = rootView.findViewById(R.id.appbarlayout);
|
|
|
|
viewPager = rootView.findViewById(R.id.viewpager);
|
2020-09-06 14:01:59 +02:00
|
|
|
pageAdapter = new TabAdapter(getChildFragmentManager());
|
2018-10-02 17:09:16 +02:00
|
|
|
viewPager.setAdapter(pageAdapter);
|
|
|
|
tabLayout = rootView.findViewById(R.id.tablayout);
|
|
|
|
tabLayout.setupWithViewPager(viewPager);
|
2018-09-23 03:32:19 +02:00
|
|
|
|
2018-12-08 22:51:55 +01:00
|
|
|
relatedStreamsLayout = rootView.findViewById(R.id.relatedStreamsLayout);
|
|
|
|
|
2019-09-23 12:20:15 +02:00
|
|
|
thumbnailBackgroundButton.requestFocus();
|
2020-04-22 22:35:33 +02:00
|
|
|
|
2020-07-21 00:43:49 +02:00
|
|
|
if (DeviceUtils.isTv(getContext())) {
|
2020-04-22 22:35:33 +02:00
|
|
|
// remove ripple effects from detail controls
|
|
|
|
final int transparent = getResources().getColor(R.color.transparent_background_color);
|
|
|
|
detailControlsAddToPlaylist.setBackgroundColor(transparent);
|
|
|
|
detailControlsBackground.setBackgroundColor(transparent);
|
|
|
|
detailControlsPopup.setBackgroundColor(transparent);
|
|
|
|
detailControlsDownload.setBackgroundColor(transparent);
|
|
|
|
}
|
|
|
|
|
2018-09-23 03:32:19 +02:00
|
|
|
}
|
|
|
|
|
2017-09-03 08:04:18 +02:00
|
|
|
@Override
|
2017-04-26 21:32:04 +02:00
|
|
|
protected void initListeners() {
|
|
|
|
super.initListeners();
|
2017-03-31 20:15:26 +02:00
|
|
|
|
2020-06-10 23:11:06 +02:00
|
|
|
videoTitleRoot.setOnLongClickListener(this);
|
2017-06-15 16:26:48 +02:00
|
|
|
uploaderRootLayout.setOnClickListener(this);
|
2020-04-19 23:01:02 +02:00
|
|
|
uploaderRootLayout.setOnLongClickListener(this);
|
2017-04-26 21:32:04 +02:00
|
|
|
videoTitleRoot.setOnClickListener(this);
|
|
|
|
thumbnailBackgroundButton.setOnClickListener(this);
|
|
|
|
detailControlsBackground.setOnClickListener(this);
|
|
|
|
detailControlsPopup.setOnClickListener(this);
|
2018-01-17 23:32:09 +01:00
|
|
|
detailControlsAddToPlaylist.setOnClickListener(this);
|
2018-02-11 21:34:32 +01:00
|
|
|
detailControlsDownload.setOnClickListener(this);
|
2018-04-08 21:53:15 +02:00
|
|
|
detailControlsDownload.setOnLongClickListener(this);
|
2017-10-13 02:02:07 +02:00
|
|
|
|
|
|
|
detailControlsBackground.setLongClickable(true);
|
|
|
|
detailControlsPopup.setLongClickable(true);
|
|
|
|
detailControlsBackground.setOnLongClickListener(this);
|
|
|
|
detailControlsPopup.setOnLongClickListener(this);
|
2019-12-29 22:15:01 +01:00
|
|
|
|
|
|
|
overlayThumbnailImageView.setOnClickListener(this);
|
|
|
|
overlayThumbnailImageView.setOnLongClickListener(this);
|
|
|
|
overlayMetadata.setOnClickListener(this);
|
|
|
|
overlayMetadata.setOnLongClickListener(this);
|
|
|
|
overlayButtons.setOnClickListener(this);
|
|
|
|
overlayCloseButton.setOnClickListener(this);
|
|
|
|
overlayPlayPauseButton.setOnClickListener(this);
|
|
|
|
|
2017-10-14 23:09:49 +02:00
|
|
|
detailControlsBackground.setOnTouchListener(getOnControlsTouchListener());
|
|
|
|
detailControlsPopup.setOnTouchListener(getOnControlsTouchListener());
|
2019-12-29 22:15:01 +01:00
|
|
|
|
|
|
|
setupBottomPlayer();
|
2020-09-17 22:42:35 +02:00
|
|
|
if (!PlayerHolder.bound) {
|
|
|
|
setHeightThumbnail();
|
|
|
|
} else {
|
|
|
|
PlayerHolder.startService(App.getApp(), false, this);
|
|
|
|
}
|
2017-10-14 23:09:49 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
private View.OnTouchListener getOnControlsTouchListener() {
|
2020-11-20 00:54:27 +01:00
|
|
|
return (view, motionEvent) -> {
|
2018-02-16 11:31:25 +01:00
|
|
|
if (!PreferenceManager.getDefaultSharedPreferences(activity)
|
|
|
|
.getBoolean(getString(R.string.show_hold_to_append_key), true)) {
|
|
|
|
return false;
|
|
|
|
}
|
2018-02-11 21:34:32 +01:00
|
|
|
|
|
|
|
if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) {
|
2018-02-12 00:43:12 +01:00
|
|
|
animateView(appendControlsDetail, true, 250, 0, () ->
|
|
|
|
animateView(appendControlsDetail, false, 1500, 1000));
|
2017-10-14 23:09:49 +02:00
|
|
|
}
|
2018-02-11 21:34:32 +01:00
|
|
|
return false;
|
2017-10-14 23:09:49 +02:00
|
|
|
};
|
2017-03-31 20:15:26 +02:00
|
|
|
}
|
|
|
|
|
2020-03-31 19:20:15 +02:00
|
|
|
private void initThumbnailViews(@NonNull final StreamInfo info) {
|
2017-09-03 08:04:18 +02:00
|
|
|
thumbnailImageView.setImageResource(R.drawable.dummy_thumbnail_dark);
|
2019-12-29 22:15:01 +01:00
|
|
|
|
2020-12-15 17:41:21 +01:00
|
|
|
if (!isEmpty(info.getThumbnailUrl())) {
|
2018-03-23 02:11:59 +01:00
|
|
|
final String infoServiceName = NewPipe.getNameOfService(info.getServiceId());
|
|
|
|
final ImageLoadingListener onFailListener = new SimpleImageLoadingListener() {
|
2017-04-26 21:32:04 +02:00
|
|
|
@Override
|
2020-03-31 19:20:15 +02:00
|
|
|
public void onLoadingFailed(final String imageUri, final View view,
|
|
|
|
final FailReason failReason) {
|
2018-03-23 02:11:59 +01:00
|
|
|
showSnackBarError(failReason.getCause(), UserAction.LOAD_IMAGE,
|
|
|
|
infoServiceName, imageUri, R.string.could_not_load_thumbnails);
|
2017-04-26 21:32:04 +02:00
|
|
|
}
|
2018-03-23 02:11:59 +01:00
|
|
|
};
|
|
|
|
|
2020-03-31 19:20:15 +02:00
|
|
|
IMAGE_LOADER.displayImage(info.getThumbnailUrl(), thumbnailImageView,
|
2018-03-23 02:11:59 +01:00
|
|
|
ImageDisplayConstants.DISPLAY_THUMBNAIL_OPTIONS, onFailListener);
|
2017-09-03 08:04:18 +02:00
|
|
|
}
|
2018-02-16 11:31:25 +01:00
|
|
|
|
2020-12-15 17:41:21 +01:00
|
|
|
if (!isEmpty(info.getSubChannelAvatarUrl())) {
|
2020-04-16 17:35:42 +02:00
|
|
|
IMAGE_LOADER.displayImage(info.getSubChannelAvatarUrl(), subChannelThumb,
|
2020-04-13 22:40:44 +02:00
|
|
|
ImageDisplayConstants.DISPLAY_AVATAR_OPTIONS);
|
2017-09-03 08:04:18 +02:00
|
|
|
}
|
2018-02-16 11:31:25 +01:00
|
|
|
|
2020-12-15 17:41:21 +01:00
|
|
|
if (!isEmpty(info.getUploaderAvatarUrl())) {
|
2020-03-31 19:20:15 +02:00
|
|
|
IMAGE_LOADER.displayImage(info.getUploaderAvatarUrl(), uploaderThumb,
|
2018-03-16 04:07:20 +01:00
|
|
|
ImageDisplayConstants.DISPLAY_AVATAR_OPTIONS);
|
2017-03-31 20:15:26 +02:00
|
|
|
}
|
2016-01-01 23:04:29 +01:00
|
|
|
}
|
|
|
|
|
2017-04-09 19:34:00 +02:00
|
|
|
/*//////////////////////////////////////////////////////////////////////////
|
|
|
|
// OwnStack
|
|
|
|
//////////////////////////////////////////////////////////////////////////*/
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Stack that contains the "navigation history".<br>
|
|
|
|
* The peek is the current video.
|
|
|
|
*/
|
2020-09-17 22:42:35 +02:00
|
|
|
private static LinkedList<StackItem> stack = new LinkedList<>();
|
2017-04-09 19:34:00 +02:00
|
|
|
|
2015-09-04 02:15:03 +02:00
|
|
|
@Override
|
2020-07-13 03:17:21 +02:00
|
|
|
public boolean onKeyDown(final int keyCode) {
|
|
|
|
return player != null && player.onKeyDown(keyCode);
|
2017-03-31 20:15:26 +02:00
|
|
|
}
|
2017-04-26 21:32:04 +02:00
|
|
|
|
2017-09-03 08:04:18 +02:00
|
|
|
@Override
|
|
|
|
public boolean onBackPressed() {
|
|
|
|
if (DEBUG) {
|
2020-07-13 03:17:21 +02:00
|
|
|
Log.d(TAG, "onBackPressed() called");
|
2017-04-09 19:34:00 +02:00
|
|
|
}
|
2019-12-29 22:15:01 +01:00
|
|
|
|
2020-01-06 11:39:01 +01:00
|
|
|
// If we are in fullscreen mode just exit from it via first back press
|
2020-06-27 05:25:50 +02:00
|
|
|
if (player != null && player.isFullscreen()) {
|
2020-07-21 00:43:49 +02:00
|
|
|
if (!DeviceUtils.isTablet(activity)) {
|
2021-01-08 18:35:33 +01:00
|
|
|
player.pause();
|
2020-07-14 19:21:32 +02:00
|
|
|
}
|
2019-12-29 22:15:01 +01:00
|
|
|
restoreDefaultOrientation();
|
2020-10-18 20:19:50 +02:00
|
|
|
setAutoPlay(false);
|
2019-12-29 22:15:01 +01:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2020-01-06 11:39:01 +01:00
|
|
|
// If we have something in history of played items we replay it here
|
2020-06-27 05:25:50 +02:00
|
|
|
if (player != null
|
2020-03-10 10:06:38 +01:00
|
|
|
&& player.getPlayQueue() != null
|
|
|
|
&& player.videoPlayerSelected()
|
2020-06-27 05:25:50 +02:00
|
|
|
&& player.getPlayQueue().previous()) {
|
2020-01-06 11:39:01 +01:00
|
|
|
return true;
|
|
|
|
}
|
2017-04-09 19:34:00 +02:00
|
|
|
// That means that we are on the start of the stack,
|
|
|
|
// return false to let the MainActivity handle the onBack
|
2019-12-29 22:15:01 +01:00
|
|
|
if (stack.size() <= 1) {
|
|
|
|
restoreDefaultOrientation();
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
2017-04-09 19:34:00 +02:00
|
|
|
// Remove top
|
|
|
|
stack.pop();
|
2017-09-03 08:04:18 +02:00
|
|
|
// Get stack item from the new top
|
2020-07-12 02:59:47 +02:00
|
|
|
assert stack.peek() != null;
|
2020-01-09 16:28:06 +01:00
|
|
|
setupFromHistoryItem(stack.peek());
|
2017-04-26 21:32:04 +02:00
|
|
|
|
2020-01-09 16:28:06 +01:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2020-07-12 02:59:47 +02:00
|
|
|
private void setupFromHistoryItem(final StackItem item) {
|
2020-10-18 20:19:50 +02:00
|
|
|
setAutoPlay(false);
|
2019-12-29 22:15:01 +01:00
|
|
|
hideMainPlayer();
|
|
|
|
|
2020-10-18 20:19:50 +02:00
|
|
|
setInitialData(item.getServiceId(), item.getUrl(),
|
|
|
|
item.getTitle() == null ? "" : item.getTitle(), item.getPlayQueue());
|
2020-03-10 10:06:38 +01:00
|
|
|
startLoading(false);
|
|
|
|
|
|
|
|
// Maybe an item was deleted in background activity
|
2020-07-14 19:21:32 +02:00
|
|
|
if (item.getPlayQueue().getItem() == null) {
|
|
|
|
return;
|
|
|
|
}
|
2020-02-05 06:59:30 +01:00
|
|
|
|
2020-07-12 02:59:47 +02:00
|
|
|
final PlayQueueItem playQueueItem = item.getPlayQueue().getItem();
|
2020-02-05 06:59:30 +01:00
|
|
|
// Update title, url, uploader from the last item in the stack (it's current now)
|
2021-01-08 18:35:33 +01:00
|
|
|
final boolean isPlayerStopped = player == null || player.isStopped();
|
2020-07-14 19:21:32 +02:00
|
|
|
if (playQueueItem != null && isPlayerStopped) {
|
|
|
|
updateOverlayData(playQueueItem.getTitle(),
|
|
|
|
playQueueItem.getUploader(), playQueueItem.getThumbnailUrl());
|
|
|
|
}
|
2017-04-09 19:34:00 +02:00
|
|
|
}
|
|
|
|
|
2017-03-31 20:15:26 +02:00
|
|
|
/*//////////////////////////////////////////////////////////////////////////
|
2017-09-03 08:04:18 +02:00
|
|
|
// Info loading and handling
|
2017-03-31 20:15:26 +02:00
|
|
|
//////////////////////////////////////////////////////////////////////////*/
|
|
|
|
|
2017-09-03 08:04:18 +02:00
|
|
|
@Override
|
|
|
|
protected void doInitialLoadLogic() {
|
2020-07-14 19:21:32 +02:00
|
|
|
if (wasCleared()) {
|
|
|
|
return;
|
|
|
|
}
|
2019-12-29 22:15:01 +01:00
|
|
|
|
2020-03-31 19:20:15 +02:00
|
|
|
if (currentInfo == null) {
|
|
|
|
prepareAndLoadInfo();
|
|
|
|
} else {
|
2020-09-17 22:42:35 +02:00
|
|
|
prepareAndHandleInfoIfNeededAfterDelay(currentInfo, false, 50);
|
2020-03-31 19:20:15 +02:00
|
|
|
}
|
2017-03-31 20:15:26 +02:00
|
|
|
}
|
|
|
|
|
2020-10-18 20:19:50 +02:00
|
|
|
public void selectAndLoadVideo(final int newServiceId,
|
|
|
|
@Nullable final String newUrl,
|
|
|
|
@NonNull final String newTitle,
|
|
|
|
@Nullable final PlayQueue newQueue) {
|
|
|
|
if (player != null && newQueue != null && playQueue != null
|
|
|
|
&& !Objects.equals(newQueue.getItem(), playQueue.getItem())) {
|
|
|
|
// Preloading can be disabled since playback is surely being replaced.
|
2020-09-07 18:34:10 +02:00
|
|
|
player.disablePreloadingOfCurrentTrack();
|
|
|
|
}
|
2020-10-18 20:19:50 +02:00
|
|
|
|
|
|
|
setInitialData(newServiceId, newUrl, newTitle, newQueue);
|
2020-03-10 10:06:38 +01:00
|
|
|
startLoading(false, true);
|
2017-04-09 19:34:00 +02:00
|
|
|
}
|
|
|
|
|
2020-09-17 22:42:35 +02:00
|
|
|
private void prepareAndHandleInfoIfNeededAfterDelay(final StreamInfo info,
|
|
|
|
final boolean scrollToTop,
|
|
|
|
final long delay) {
|
|
|
|
new Handler(Looper.getMainLooper()).postDelayed(() -> {
|
|
|
|
if (activity == null) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
// Data can already be drawn, don't spend time twice
|
|
|
|
if (info.getName().equals(videoTitleTextView.getText().toString())) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
prepareAndHandleInfo(info, scrollToTop);
|
|
|
|
}, delay);
|
|
|
|
}
|
|
|
|
|
2020-04-02 13:51:10 +02:00
|
|
|
private void prepareAndHandleInfo(final StreamInfo info, final boolean scrollToTop) {
|
2020-03-31 19:20:15 +02:00
|
|
|
if (DEBUG) {
|
|
|
|
Log.d(TAG, "prepareAndHandleInfo() called with: "
|
|
|
|
+ "info = [" + info + "], scrollToTop = [" + scrollToTop + "]");
|
|
|
|
}
|
2017-04-28 05:58:50 +02:00
|
|
|
|
2017-09-03 08:04:18 +02:00
|
|
|
showLoading();
|
2018-10-02 17:09:16 +02:00
|
|
|
initTabs();
|
2017-04-26 21:32:04 +02:00
|
|
|
|
2020-07-14 19:21:32 +02:00
|
|
|
if (scrollToTop) {
|
|
|
|
scrollToTop();
|
|
|
|
}
|
2018-12-19 06:28:59 +01:00
|
|
|
handleResult(info);
|
|
|
|
showContent();
|
|
|
|
|
2017-04-09 19:34:00 +02:00
|
|
|
}
|
2017-03-31 20:15:26 +02:00
|
|
|
|
2017-09-03 08:04:18 +02:00
|
|
|
protected void prepareAndLoadInfo() {
|
2019-12-31 17:06:39 +01:00
|
|
|
scrollToTop();
|
2017-09-03 08:04:18 +02:00
|
|
|
startLoading(false);
|
|
|
|
}
|
2017-04-28 05:58:50 +02:00
|
|
|
|
2017-09-03 08:04:18 +02:00
|
|
|
@Override
|
2020-07-12 02:59:47 +02:00
|
|
|
public void startLoading(final boolean forceLoad) {
|
2017-09-03 08:04:18 +02:00
|
|
|
super.startLoading(forceLoad);
|
|
|
|
|
2018-10-02 17:09:16 +02:00
|
|
|
initTabs();
|
2017-09-03 08:04:18 +02:00
|
|
|
currentInfo = null;
|
2020-03-31 19:20:15 +02:00
|
|
|
if (currentWorker != null) {
|
|
|
|
currentWorker.dispose();
|
|
|
|
}
|
2017-09-03 08:04:18 +02:00
|
|
|
|
2020-03-10 10:06:38 +01:00
|
|
|
runWorker(forceLoad, stack.isEmpty());
|
|
|
|
}
|
|
|
|
|
2020-07-12 02:59:47 +02:00
|
|
|
private void startLoading(final boolean forceLoad, final boolean addToBackStack) {
|
2020-07-14 19:21:32 +02:00
|
|
|
super.startLoading(forceLoad);
|
2020-03-10 10:06:38 +01:00
|
|
|
|
|
|
|
initTabs();
|
|
|
|
currentInfo = null;
|
2020-07-14 19:21:32 +02:00
|
|
|
if (currentWorker != null) {
|
|
|
|
currentWorker.dispose();
|
|
|
|
}
|
2020-03-10 10:06:38 +01:00
|
|
|
|
|
|
|
runWorker(forceLoad, addToBackStack);
|
|
|
|
}
|
|
|
|
|
2020-07-12 02:59:47 +02:00
|
|
|
private void runWorker(final boolean forceLoad, final boolean addToBackStack) {
|
2020-07-13 03:17:21 +02:00
|
|
|
final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(activity);
|
2017-09-03 08:04:18 +02:00
|
|
|
currentWorker = ExtractorHelper.getStreamInfo(serviceId, url, forceLoad)
|
|
|
|
.subscribeOn(Schedulers.io())
|
|
|
|
.observeOn(AndroidSchedulers.mainThread())
|
2020-11-20 00:54:27 +01:00
|
|
|
.subscribe(result -> {
|
2018-02-11 21:34:32 +01:00
|
|
|
isLoading.set(false);
|
2019-12-29 22:15:01 +01:00
|
|
|
hideMainPlayer();
|
2020-04-10 14:25:00 +02:00
|
|
|
if (result.getAgeLimit() != NO_AGE_LIMIT && !prefs.getBoolean(
|
|
|
|
getString(R.string.show_age_restricted_content), false)) {
|
2020-04-11 09:30:12 +02:00
|
|
|
hideAgeRestrictedContent();
|
2020-04-10 14:25:00 +02:00
|
|
|
} else {
|
|
|
|
handleResult(result);
|
|
|
|
showContent();
|
2020-07-13 03:17:21 +02:00
|
|
|
if (addToBackStack) {
|
2020-07-14 19:21:32 +02:00
|
|
|
if (playQueue == null) {
|
|
|
|
playQueue = new SinglePlayQueue(result);
|
|
|
|
}
|
|
|
|
if (stack.isEmpty() || !stack.peek().getPlayQueue().equals(playQueue)) {
|
2020-10-18 20:19:50 +02:00
|
|
|
stack.push(new StackItem(serviceId, url, title, playQueue));
|
2020-07-14 19:21:32 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if (isAutoplayEnabled()) {
|
|
|
|
openVideoPlayer();
|
2020-07-13 03:17:21 +02:00
|
|
|
}
|
2020-03-10 10:06:38 +01:00
|
|
|
}
|
2020-11-20 00:54:27 +01:00
|
|
|
}, throwable -> {
|
2018-02-11 21:34:32 +01:00
|
|
|
isLoading.set(false);
|
|
|
|
onError(throwable);
|
2017-09-03 08:04:18 +02:00
|
|
|
});
|
2018-10-02 17:09:16 +02:00
|
|
|
}
|
2018-09-23 03:32:19 +02:00
|
|
|
|
2018-10-02 17:09:16 +02:00
|
|
|
private void initTabs() {
|
2019-03-24 02:01:28 +01:00
|
|
|
if (pageAdapter.getCount() != 0) {
|
|
|
|
selectedTabTag = pageAdapter.getItemTitle(viewPager.getCurrentItem());
|
|
|
|
}
|
2018-10-02 17:09:16 +02:00
|
|
|
pageAdapter.clearAllItems();
|
|
|
|
|
2020-07-12 02:59:47 +02:00
|
|
|
if (shouldShowComments()) {
|
2020-07-14 19:21:32 +02:00
|
|
|
pageAdapter.addFragment(
|
2020-10-18 20:19:50 +02:00
|
|
|
CommentsFragment.getInstance(serviceId, url, title), COMMENTS_TAB_TAG);
|
2018-10-02 17:09:16 +02:00
|
|
|
}
|
|
|
|
|
2020-07-12 02:59:47 +02:00
|
|
|
if (showRelatedStreams && null == relatedStreamsLayout) {
|
2018-10-02 17:26:14 +02:00
|
|
|
//temp empty fragment. will be updated in handleResult
|
2018-10-02 17:09:16 +02:00
|
|
|
pageAdapter.addFragment(new Fragment(), RELATED_TAB_TAG);
|
|
|
|
}
|
|
|
|
|
2020-07-12 02:59:47 +02:00
|
|
|
if (pageAdapter.getCount() == 0) {
|
2019-03-03 13:50:15 +01:00
|
|
|
pageAdapter.addFragment(new EmptyFragment(), EMPTY_TAB_TAG);
|
|
|
|
}
|
|
|
|
|
2018-10-02 18:00:11 +02:00
|
|
|
pageAdapter.notifyDataSetUpdate();
|
|
|
|
|
2020-07-12 02:59:47 +02:00
|
|
|
if (pageAdapter.getCount() < 2) {
|
2018-10-02 17:09:16 +02:00
|
|
|
tabLayout.setVisibility(View.GONE);
|
2020-07-12 02:59:47 +02:00
|
|
|
} else {
|
2020-08-16 10:24:58 +02:00
|
|
|
final int position = pageAdapter.getItemPositionByTitle(selectedTabTag);
|
2020-03-31 19:20:15 +02:00
|
|
|
if (position != -1) {
|
|
|
|
viewPager.setCurrentItem(position);
|
|
|
|
}
|
2018-10-02 17:26:14 +02:00
|
|
|
tabLayout.setVisibility(View.VISIBLE);
|
2018-10-02 17:09:16 +02:00
|
|
|
}
|
2018-09-23 03:32:19 +02:00
|
|
|
}
|
|
|
|
|
2018-10-02 17:09:16 +02:00
|
|
|
private boolean shouldShowComments() {
|
|
|
|
try {
|
2019-02-15 20:53:26 +01:00
|
|
|
return showComments && NewPipe.getService(serviceId)
|
|
|
|
.getServiceInfo()
|
|
|
|
.getMediaCapabilities()
|
|
|
|
.contains(COMMENTS);
|
2020-08-16 10:24:58 +02:00
|
|
|
} catch (final ExtractionException e) {
|
2018-10-02 17:09:16 +02:00
|
|
|
return false;
|
2018-09-23 03:32:19 +02:00
|
|
|
}
|
2017-09-03 08:04:18 +02:00
|
|
|
}
|
2017-04-28 05:58:50 +02:00
|
|
|
|
2019-12-31 17:06:39 +01:00
|
|
|
public void scrollToTop() {
|
|
|
|
appBarLayout.setExpanded(true, true);
|
|
|
|
}
|
|
|
|
|
2017-09-03 08:04:18 +02:00
|
|
|
/*//////////////////////////////////////////////////////////////////////////
|
|
|
|
// Play Utils
|
|
|
|
//////////////////////////////////////////////////////////////////////////*/
|
2017-04-09 19:34:00 +02:00
|
|
|
|
2017-10-13 02:02:07 +02:00
|
|
|
private void openBackgroundPlayer(final boolean append) {
|
2020-07-12 02:59:47 +02:00
|
|
|
final AudioStream audioStream = currentInfo.getAudioStreams()
|
2018-02-16 11:31:25 +01:00
|
|
|
.get(ListHelper.getDefaultAudioFormat(activity, currentInfo.getAudioStreams()));
|
2017-03-31 20:15:26 +02:00
|
|
|
|
2020-07-14 19:21:32 +02:00
|
|
|
final boolean useExternalAudioPlayer = PreferenceManager
|
|
|
|
.getDefaultSharedPreferences(activity)
|
2017-09-03 08:04:18 +02:00
|
|
|
.getBoolean(activity.getString(R.string.use_external_audio_player_key), false);
|
2017-04-28 05:58:50 +02:00
|
|
|
|
2020-07-14 19:21:32 +02:00
|
|
|
// If a user watched video inside fullscreen mode and than chose another player
|
|
|
|
// return to non-fullscreen mode
|
|
|
|
if (player != null && player.isFullscreen()) {
|
|
|
|
player.toggleFullscreen();
|
|
|
|
}
|
2019-12-31 03:07:07 +01:00
|
|
|
|
2020-08-27 22:55:57 +02:00
|
|
|
if (!useExternalAudioPlayer) {
|
2017-10-13 02:02:07 +02:00
|
|
|
openNormalBackgroundPlayer(append);
|
2017-04-26 21:32:04 +02:00
|
|
|
} else {
|
2018-06-19 03:27:30 +02:00
|
|
|
startOnExternalPlayer(activity, currentInfo, audioStream);
|
2017-04-26 21:32:04 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-10-13 02:02:07 +02:00
|
|
|
private void openPopupPlayer(final boolean append) {
|
2018-01-04 07:53:31 +01:00
|
|
|
if (!PermissionHelper.isPopupEnabled(activity)) {
|
|
|
|
PermissionHelper.showPopupEnablementToast(activity);
|
2017-09-03 08:04:18 +02:00
|
|
|
return;
|
|
|
|
}
|
2017-04-26 21:32:04 +02:00
|
|
|
|
2019-12-29 22:15:01 +01:00
|
|
|
// See UI changes while remote playQueue changes
|
2020-09-17 22:42:35 +02:00
|
|
|
if (player == null) {
|
|
|
|
PlayerHolder.startService(App.getApp(), false, this);
|
2020-07-14 19:21:32 +02:00
|
|
|
}
|
2019-12-29 22:15:01 +01:00
|
|
|
|
2020-07-14 19:21:32 +02:00
|
|
|
// If a user watched video inside fullscreen mode and than chose another player
|
|
|
|
// return to non-fullscreen mode
|
|
|
|
if (player != null && player.isFullscreen()) {
|
|
|
|
player.toggleFullscreen();
|
|
|
|
}
|
2019-12-31 03:07:07 +01:00
|
|
|
|
2020-07-12 02:59:47 +02:00
|
|
|
final PlayQueue queue = setupPlayQueueForIntent(append);
|
2017-10-13 02:02:07 +02:00
|
|
|
if (append) {
|
2019-12-29 22:15:01 +01:00
|
|
|
NavigationHelper.enqueueOnPopupPlayer(activity, queue, false);
|
2017-10-13 02:02:07 +02:00
|
|
|
} else {
|
2020-07-14 19:21:32 +02:00
|
|
|
replaceQueueIfUserConfirms(() -> NavigationHelper
|
|
|
|
.playOnPopupPlayer(activity, queue, true));
|
2017-10-13 02:02:07 +02:00
|
|
|
}
|
2017-09-03 08:04:18 +02:00
|
|
|
}
|
2017-04-26 21:32:04 +02:00
|
|
|
|
2020-10-18 20:19:50 +02:00
|
|
|
public void openVideoPlayer() {
|
2018-02-16 11:31:25 +01:00
|
|
|
if (PreferenceManager.getDefaultSharedPreferences(activity)
|
|
|
|
.getBoolean(this.getString(R.string.use_external_video_player_key), false)) {
|
2020-07-23 23:43:09 +02:00
|
|
|
showExternalPlaybackDialog();
|
2017-04-26 21:32:04 +02:00
|
|
|
} else {
|
2020-06-27 05:25:50 +02:00
|
|
|
replaceQueueIfUserConfirms(this::openMainPlayer);
|
2017-04-26 21:32:04 +02:00
|
|
|
}
|
2017-09-03 08:04:18 +02:00
|
|
|
}
|
2017-04-26 21:32:04 +02:00
|
|
|
|
2017-10-13 02:02:07 +02:00
|
|
|
private void openNormalBackgroundPlayer(final boolean append) {
|
2019-12-29 22:15:01 +01:00
|
|
|
// See UI changes while remote playQueue changes
|
2020-09-17 22:42:35 +02:00
|
|
|
if (player == null) {
|
|
|
|
PlayerHolder.startService(App.getApp(), false, this);
|
2020-07-14 19:21:32 +02:00
|
|
|
}
|
2019-12-29 22:15:01 +01:00
|
|
|
|
2020-07-12 02:59:47 +02:00
|
|
|
final PlayQueue queue = setupPlayQueueForIntent(append);
|
2017-10-14 06:07:19 +02:00
|
|
|
if (append) {
|
2019-12-29 22:15:01 +01:00
|
|
|
NavigationHelper.enqueueOnBackgroundPlayer(activity, queue, false);
|
2017-10-14 06:07:19 +02:00
|
|
|
} else {
|
2020-07-14 19:21:32 +02:00
|
|
|
replaceQueueIfUserConfirms(() -> NavigationHelper
|
|
|
|
.playOnBackgroundPlayer(activity, queue, true));
|
2017-10-14 06:07:19 +02:00
|
|
|
}
|
2017-09-03 08:04:18 +02:00
|
|
|
}
|
2017-04-26 21:32:04 +02:00
|
|
|
|
2020-06-27 05:25:50 +02:00
|
|
|
private void openMainPlayer() {
|
2019-12-29 22:15:01 +01:00
|
|
|
if (playerService == null) {
|
2020-10-31 20:26:09 +01:00
|
|
|
PlayerHolder.startService(App.getApp(), autoPlayEnabled, this);
|
2020-07-14 19:21:32 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (currentInfo == null) {
|
2020-07-12 02:59:47 +02:00
|
|
|
return;
|
2020-01-17 15:37:53 +01:00
|
|
|
}
|
2019-12-29 22:15:01 +01:00
|
|
|
|
2020-07-12 02:59:47 +02:00
|
|
|
final PlayQueue queue = setupPlayQueueForIntent(false);
|
2019-12-29 22:15:01 +01:00
|
|
|
|
2020-07-14 19:21:32 +02:00
|
|
|
// Video view can have elements visible from popup,
|
|
|
|
// We hide it here but once it ready the view will be shown in handleIntent()
|
2020-11-02 18:06:14 +01:00
|
|
|
if (playerService.getView() != null) {
|
|
|
|
playerService.getView().setVisibility(View.GONE);
|
|
|
|
}
|
2020-01-17 15:37:53 +01:00
|
|
|
addVideoPlayerView();
|
2019-12-29 22:15:01 +01:00
|
|
|
|
2020-07-14 19:21:32 +02:00
|
|
|
final Intent playerIntent = NavigationHelper
|
2020-10-31 20:26:09 +01:00
|
|
|
.getPlayerIntent(requireContext(), MainPlayer.class, queue, true, autoPlayEnabled);
|
2020-01-17 15:37:53 +01:00
|
|
|
activity.startService(playerIntent);
|
2019-12-29 22:15:01 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
private void hideMainPlayer() {
|
2020-07-14 19:21:32 +02:00
|
|
|
if (playerService == null
|
|
|
|
|| playerService.getView() == null
|
|
|
|
|| !player.videoPlayerSelected()) {
|
2019-12-29 22:15:01 +01:00
|
|
|
return;
|
2020-07-14 19:21:32 +02:00
|
|
|
}
|
2019-12-29 22:15:01 +01:00
|
|
|
|
|
|
|
removeVideoPlayerView();
|
2020-01-15 19:32:29 +01:00
|
|
|
playerService.stop(isAutoplayEnabled());
|
2019-12-29 22:15:01 +01:00
|
|
|
playerService.getView().setVisibility(View.GONE);
|
|
|
|
}
|
|
|
|
|
2020-07-12 02:59:47 +02:00
|
|
|
private PlayQueue setupPlayQueueForIntent(final boolean append) {
|
2020-07-14 19:21:32 +02:00
|
|
|
if (append) {
|
|
|
|
return new SinglePlayQueue(currentInfo);
|
|
|
|
}
|
2019-12-29 22:15:01 +01:00
|
|
|
|
|
|
|
PlayQueue queue = playQueue;
|
|
|
|
// Size can be 0 because queue removes bad stream automatically when error occurs
|
2020-11-18 23:54:16 +01:00
|
|
|
if (queue == null || queue.isEmpty()) {
|
2019-12-29 22:15:01 +01:00
|
|
|
queue = new SinglePlayQueue(currentInfo);
|
2020-07-14 19:21:32 +02:00
|
|
|
}
|
2019-12-29 22:15:01 +01:00
|
|
|
|
|
|
|
return queue;
|
|
|
|
}
|
|
|
|
|
2017-09-03 08:04:18 +02:00
|
|
|
/*//////////////////////////////////////////////////////////////////////////
|
|
|
|
// Utils
|
|
|
|
//////////////////////////////////////////////////////////////////////////*/
|
|
|
|
|
2020-10-18 20:19:50 +02:00
|
|
|
public void setAutoPlay(final boolean autoPlay) {
|
|
|
|
this.autoPlayEnabled = autoPlay;
|
2017-03-31 20:15:26 +02:00
|
|
|
}
|
|
|
|
|
2018-06-19 03:27:30 +02:00
|
|
|
private void startOnExternalPlayer(@NonNull final Context context,
|
|
|
|
@NonNull final StreamInfo info,
|
|
|
|
@NonNull final Stream selectedStream) {
|
|
|
|
NavigationHelper.playOnExternalPlayer(context, currentInfo.getName(),
|
2020-04-16 17:35:42 +02:00
|
|
|
currentInfo.getSubChannelName(), selectedStream);
|
2018-06-19 03:27:30 +02:00
|
|
|
|
|
|
|
final HistoryRecordManager recordManager = new HistoryRecordManager(requireContext());
|
|
|
|
disposables.add(recordManager.onViewed(info).onErrorComplete()
|
|
|
|
.subscribe(
|
2020-03-31 19:20:15 +02:00
|
|
|
ignored -> { /* successful */ },
|
2018-06-19 03:27:30 +02:00
|
|
|
error -> Log.e(TAG, "Register view failure: ", error)
|
|
|
|
));
|
|
|
|
}
|
|
|
|
|
2019-12-29 22:15:01 +01:00
|
|
|
private boolean isExternalPlayerEnabled() {
|
2020-09-09 20:45:42 +02:00
|
|
|
return PreferenceManager.getDefaultSharedPreferences(requireContext())
|
2019-12-29 22:15:01 +01:00
|
|
|
.getBoolean(getString(R.string.use_external_video_player_key), false);
|
|
|
|
}
|
|
|
|
|
2020-10-18 20:19:50 +02:00
|
|
|
// This method overrides default behaviour when setAutoPlay() is called.
|
2020-01-08 17:16:50 +01:00
|
|
|
// Don't auto play if the user selected an external player or disabled it in settings
|
2019-12-29 22:15:01 +01:00
|
|
|
private boolean isAutoplayEnabled() {
|
2020-01-13 17:24:28 +01:00
|
|
|
return autoPlayEnabled
|
2020-01-08 17:16:50 +01:00
|
|
|
&& !isExternalPlayerEnabled()
|
2020-01-09 16:28:06 +01:00
|
|
|
&& (player == null || player.videoPlayerSelected())
|
2020-01-26 05:33:52 +01:00
|
|
|
&& bottomSheetState != BottomSheetBehavior.STATE_HIDDEN
|
2020-09-09 20:45:42 +02:00
|
|
|
&& PlayerHelper.isAutoplayAllowedByUser(requireContext());
|
2019-12-29 22:15:01 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
private void addVideoPlayerView() {
|
2020-07-14 19:21:32 +02:00
|
|
|
if (player == null || getView() == null) {
|
|
|
|
return;
|
|
|
|
}
|
2019-12-29 22:15:01 +01:00
|
|
|
|
|
|
|
// Check if viewHolder already contains a child
|
2020-08-05 11:46:25 +02:00
|
|
|
if (player.getRootView().getParent() != playerPlaceholder) {
|
2020-09-17 22:42:35 +02:00
|
|
|
playerService.removeViewFromParent();
|
2020-07-14 19:21:32 +02:00
|
|
|
}
|
2019-12-31 03:07:07 +01:00
|
|
|
setHeightThumbnail();
|
2019-12-29 22:15:01 +01:00
|
|
|
|
|
|
|
// Prevent from re-adding a view multiple times
|
2020-07-14 19:21:32 +02:00
|
|
|
if (player.getRootView().getParent() == null) {
|
2020-08-05 11:46:25 +02:00
|
|
|
playerPlaceholder.addView(player.getRootView());
|
2020-07-14 19:21:32 +02:00
|
|
|
}
|
2019-12-29 22:15:01 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
private void removeVideoPlayerView() {
|
|
|
|
makeDefaultHeightForVideoPlaceholder();
|
|
|
|
|
|
|
|
playerService.removeViewFromParent();
|
|
|
|
}
|
|
|
|
|
|
|
|
private void makeDefaultHeightForVideoPlaceholder() {
|
2020-07-14 19:21:32 +02:00
|
|
|
if (getView() == null) {
|
|
|
|
return;
|
|
|
|
}
|
2020-01-17 15:37:53 +01:00
|
|
|
|
2020-08-05 11:46:25 +02:00
|
|
|
playerPlaceholder.getLayoutParams().height = FrameLayout.LayoutParams.MATCH_PARENT;
|
|
|
|
playerPlaceholder.requestLayout();
|
2019-12-29 22:15:01 +01:00
|
|
|
}
|
|
|
|
|
2020-03-31 19:20:15 +02:00
|
|
|
private void prepareDescription(final Description description) {
|
2020-12-15 17:41:21 +01:00
|
|
|
if (description == null || isEmpty(description.getContent())
|
2020-03-31 19:20:15 +02:00
|
|
|
|| description == Description.emptyDescription) {
|
2017-09-03 08:04:18 +02:00
|
|
|
return;
|
2017-08-12 06:50:25 +02:00
|
|
|
}
|
2017-03-31 20:15:26 +02:00
|
|
|
|
2020-02-06 23:54:36 +01:00
|
|
|
if (description.getType() == Description.HTML) {
|
|
|
|
disposables.add(Single.just(description.getContent())
|
2020-11-20 00:54:27 +01:00
|
|
|
.map(descriptionText ->
|
2020-08-27 22:59:09 +02:00
|
|
|
HtmlCompat.fromHtml(descriptionText,
|
|
|
|
HtmlCompat.FROM_HTML_MODE_LEGACY))
|
2020-02-02 16:54:09 +01:00
|
|
|
.subscribeOn(Schedulers.computation())
|
|
|
|
.observeOn(AndroidSchedulers.mainThread())
|
2020-11-20 00:54:27 +01:00
|
|
|
.subscribe(spanned -> {
|
2020-02-02 16:54:09 +01:00
|
|
|
videoDescriptionView.setText(spanned);
|
|
|
|
videoDescriptionView.setVisibility(View.VISIBLE);
|
|
|
|
}));
|
2020-02-06 23:54:36 +01:00
|
|
|
} else if (description.getType() == Description.MARKDOWN) {
|
2020-08-27 22:55:57 +02:00
|
|
|
final Markwon markwon = Markwon.builder(requireContext())
|
2020-02-08 09:56:37 +01:00
|
|
|
.usePlugin(LinkifyPlugin.create())
|
|
|
|
.build();
|
|
|
|
markwon.setMarkdown(videoDescriptionView, description.getContent());
|
2020-02-06 23:54:36 +01:00
|
|
|
videoDescriptionView.setVisibility(View.VISIBLE);
|
|
|
|
} else {
|
|
|
|
//== Description.PLAIN_TEXT
|
2020-02-08 09:56:37 +01:00
|
|
|
videoDescriptionView.setAutoLinkMask(Linkify.WEB_URLS);
|
2020-02-06 23:54:36 +01:00
|
|
|
videoDescriptionView.setText(description.getContent(), TextView.BufferType.SPANNABLE);
|
|
|
|
videoDescriptionView.setVisibility(View.VISIBLE);
|
2020-02-02 16:54:09 +01:00
|
|
|
}
|
2017-03-31 20:15:26 +02:00
|
|
|
}
|
|
|
|
|
2020-09-17 22:42:35 +02:00
|
|
|
private final ViewTreeObserver.OnPreDrawListener preDrawListener =
|
|
|
|
new ViewTreeObserver.OnPreDrawListener() {
|
|
|
|
@Override
|
|
|
|
public boolean onPreDraw() {
|
|
|
|
final DisplayMetrics metrics = getResources().getDisplayMetrics();
|
|
|
|
|
|
|
|
if (getView() != null) {
|
2020-10-31 20:57:26 +01:00
|
|
|
final int height = (isInMultiWindow()
|
|
|
|
? requireView()
|
|
|
|
: activity.getWindow().getDecorView()).getHeight();
|
2020-09-17 22:42:35 +02:00
|
|
|
setHeightThumbnail(height, metrics);
|
|
|
|
getView().getViewTreeObserver().removeOnPreDrawListener(preDrawListener);
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2020-02-05 06:59:30 +01:00
|
|
|
/**
|
2020-07-14 19:21:32 +02:00
|
|
|
* 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
|
|
|
|
* screen orientations. It knows about multiWindow feature
|
|
|
|
* and about videos with aspectRatio ZOOM (the height for them will be a bit higher,
|
|
|
|
* {@link #MAX_PLAYER_HEIGHT})
|
2020-02-05 06:59:30 +01:00
|
|
|
*/
|
2017-03-31 20:15:26 +02:00
|
|
|
private void setHeightThumbnail() {
|
2017-09-03 08:04:18 +02:00
|
|
|
final DisplayMetrics metrics = getResources().getDisplayMetrics();
|
2020-07-12 02:59:47 +02:00
|
|
|
final boolean isPortrait = metrics.heightPixels > metrics.widthPixels;
|
2020-09-17 22:42:35 +02:00
|
|
|
requireView().getViewTreeObserver().removeOnPreDrawListener(preDrawListener);
|
2019-12-31 03:07:07 +01:00
|
|
|
|
2020-07-14 19:21:32 +02:00
|
|
|
if (player != null && player.isFullscreen()) {
|
2020-10-31 20:57:26 +01:00
|
|
|
final int height = (isInMultiWindow()
|
|
|
|
? requireView()
|
|
|
|
: activity.getWindow().getDecorView()).getHeight();
|
2020-09-17 22:42:35 +02:00
|
|
|
// Height is zero when the view is not yet displayed like after orientation change
|
|
|
|
if (height != 0) {
|
|
|
|
setHeightThumbnail(height, metrics);
|
|
|
|
} else {
|
|
|
|
requireView().getViewTreeObserver().addOnPreDrawListener(preDrawListener);
|
|
|
|
}
|
2020-07-14 19:21:32 +02:00
|
|
|
} else {
|
2020-10-31 20:57:26 +01:00
|
|
|
final int height = (int) (isPortrait
|
|
|
|
? metrics.widthPixels / (16.0f / 9.0f)
|
|
|
|
: metrics.heightPixels / 2.0f);
|
2020-09-17 22:42:35 +02:00
|
|
|
setHeightThumbnail(height, metrics);
|
2020-07-14 19:21:32 +02:00
|
|
|
}
|
2020-09-17 22:42:35 +02:00
|
|
|
}
|
2019-12-31 03:07:07 +01:00
|
|
|
|
2020-09-17 22:42:35 +02:00
|
|
|
private void setHeightThumbnail(final int newHeight, final DisplayMetrics metrics) {
|
2020-07-14 19:21:32 +02:00
|
|
|
thumbnailImageView.setLayoutParams(
|
2020-09-17 22:42:35 +02:00
|
|
|
new FrameLayout.LayoutParams(
|
|
|
|
RelativeLayout.LayoutParams.MATCH_PARENT, newHeight));
|
|
|
|
thumbnailImageView.setMinimumHeight(newHeight);
|
2020-02-05 06:59:30 +01:00
|
|
|
if (player != null) {
|
2020-07-12 02:59:47 +02:00
|
|
|
final int maxHeight = (int) (metrics.heightPixels * MAX_PLAYER_HEIGHT);
|
2020-09-17 22:42:35 +02:00
|
|
|
player.getSurfaceView()
|
|
|
|
.setHeights(newHeight, player.isFullscreen() ? newHeight : maxHeight);
|
2020-02-05 06:59:30 +01:00
|
|
|
}
|
2017-03-31 20:15:26 +02:00
|
|
|
}
|
|
|
|
|
2018-12-19 06:28:59 +01:00
|
|
|
private void showContent() {
|
2019-08-07 12:00:47 +02:00
|
|
|
contentRootLayoutHiding.setVisibility(View.VISIBLE);
|
2017-04-28 05:58:50 +02:00
|
|
|
}
|
2017-03-31 20:15:26 +02:00
|
|
|
|
2020-10-18 20:19:50 +02:00
|
|
|
protected void setInitialData(final int newServiceId,
|
|
|
|
@Nullable final String newUrl,
|
|
|
|
@NonNull final String newTitle,
|
|
|
|
@Nullable final PlayQueue newPlayQueue) {
|
|
|
|
this.serviceId = newServiceId;
|
|
|
|
this.url = newUrl;
|
|
|
|
this.title = newTitle;
|
|
|
|
this.playQueue = newPlayQueue;
|
2017-09-03 08:04:18 +02:00
|
|
|
}
|
|
|
|
|
2017-04-26 21:32:04 +02:00
|
|
|
private void setErrorImage(final int imageResource) {
|
2020-03-31 19:20:15 +02:00
|
|
|
if (thumbnailImageView == null || activity == null) {
|
|
|
|
return;
|
|
|
|
}
|
2017-09-03 08:04:18 +02:00
|
|
|
|
2020-04-06 21:07:16 +02:00
|
|
|
thumbnailImageView.setImageDrawable(
|
|
|
|
AppCompatResources.getDrawable(requireContext(), imageResource));
|
2018-02-16 11:31:25 +01:00
|
|
|
animateView(thumbnailImageView, false, 0, 0,
|
|
|
|
() -> animateView(thumbnailImageView, true, 500));
|
2017-04-26 21:32:04 +02:00
|
|
|
}
|
2017-03-31 20:15:26 +02:00
|
|
|
|
2017-04-26 21:32:04 +02:00
|
|
|
@Override
|
2020-03-31 19:20:15 +02:00
|
|
|
public void showError(final String message, final boolean showRetryButton) {
|
2017-09-03 08:04:18 +02:00
|
|
|
showError(message, showRetryButton, R.drawable.not_available_monkey);
|
|
|
|
}
|
2017-03-31 20:15:26 +02:00
|
|
|
|
2020-03-31 19:20:15 +02:00
|
|
|
protected void showError(final String message, final boolean showRetryButton,
|
|
|
|
@DrawableRes final int imageError) {
|
2017-09-03 08:04:18 +02:00
|
|
|
super.showError(message, showRetryButton);
|
|
|
|
setErrorImage(imageError);
|
2017-04-26 21:32:04 +02:00
|
|
|
}
|
2017-03-31 20:15:26 +02:00
|
|
|
|
2019-12-29 22:15:01 +01:00
|
|
|
private void setupBroadcastReceiver() {
|
|
|
|
broadcastReceiver = new BroadcastReceiver() {
|
|
|
|
@Override
|
2020-07-14 19:21:32 +02:00
|
|
|
public void onReceive(final Context context, final Intent intent) {
|
2020-11-18 23:58:41 +01:00
|
|
|
switch (intent.getAction()) {
|
|
|
|
case ACTION_SHOW_MAIN_PLAYER:
|
|
|
|
bottomSheetBehavior.setState(BottomSheetBehavior.STATE_EXPANDED);
|
|
|
|
break;
|
|
|
|
case ACTION_HIDE_MAIN_PLAYER:
|
|
|
|
bottomSheetBehavior.setState(BottomSheetBehavior.STATE_HIDDEN);
|
|
|
|
break;
|
|
|
|
case ACTION_PLAYER_STARTED:
|
|
|
|
// If the state is not hidden we don't need to show the mini player
|
|
|
|
if (bottomSheetBehavior.getState() == BottomSheetBehavior.STATE_HIDDEN) {
|
|
|
|
bottomSheetBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED);
|
|
|
|
}
|
|
|
|
// Rebound to the service if it was closed via notification or mini player
|
|
|
|
if (!PlayerHolder.bound) {
|
|
|
|
PlayerHolder.startService(
|
|
|
|
App.getApp(), false, VideoDetailFragment.this);
|
|
|
|
}
|
|
|
|
break;
|
2019-12-29 22:15:01 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
2020-08-16 10:24:58 +02:00
|
|
|
final IntentFilter intentFilter = new IntentFilter();
|
2020-01-09 16:28:06 +01:00
|
|
|
intentFilter.addAction(ACTION_SHOW_MAIN_PLAYER);
|
|
|
|
intentFilter.addAction(ACTION_HIDE_MAIN_PLAYER);
|
2020-09-29 05:22:53 +02:00
|
|
|
intentFilter.addAction(ACTION_PLAYER_STARTED);
|
2020-01-08 17:16:50 +01:00
|
|
|
activity.registerReceiver(broadcastReceiver, intentFilter);
|
2019-12-29 22:15:01 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*//////////////////////////////////////////////////////////////////////////
|
|
|
|
// Orientation listener
|
|
|
|
//////////////////////////////////////////////////////////////////////////*/
|
|
|
|
|
|
|
|
private void restoreDefaultOrientation() {
|
2020-07-14 19:21:32 +02:00
|
|
|
if (player == null || !player.videoPlayerSelected() || activity == null) {
|
|
|
|
return;
|
|
|
|
}
|
2019-12-29 22:15:01 +01:00
|
|
|
|
2020-07-14 19:21:32 +02:00
|
|
|
if (player != null && player.isFullscreen()) {
|
|
|
|
player.toggleFullscreen();
|
|
|
|
}
|
2019-12-29 22:15:01 +01:00
|
|
|
// This will show systemUI and pause the player.
|
|
|
|
// User can tap on Play button and video will be in fullscreen mode again
|
2020-07-14 19:21:32 +02:00
|
|
|
// Note for tablet: trying to avoid orientation changes since it's not easy
|
|
|
|
// to physically rotate the tablet every time
|
2020-07-21 00:43:49 +02:00
|
|
|
if (!DeviceUtils.isTablet(activity)) {
|
2020-01-17 15:37:53 +01:00
|
|
|
activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
|
2020-07-14 19:21:32 +02:00
|
|
|
}
|
2019-12-29 22:15:01 +01:00
|
|
|
}
|
|
|
|
|
2017-06-28 03:39:33 +02:00
|
|
|
/*//////////////////////////////////////////////////////////////////////////
|
2017-09-03 08:04:18 +02:00
|
|
|
// Contract
|
2017-06-28 03:39:33 +02:00
|
|
|
//////////////////////////////////////////////////////////////////////////*/
|
|
|
|
|
2017-04-26 21:32:04 +02:00
|
|
|
@Override
|
2017-09-03 08:04:18 +02:00
|
|
|
public void showLoading() {
|
2019-08-07 12:00:47 +02:00
|
|
|
|
2017-09-03 08:04:18 +02:00
|
|
|
super.showLoading();
|
2017-04-09 19:34:00 +02:00
|
|
|
|
2019-08-07 12:00:47 +02:00
|
|
|
//if data is already cached, transition from VISIBLE -> INVISIBLE -> VISIBLE is not required
|
2020-07-12 02:59:47 +02:00
|
|
|
if (!ExtractorHelper.isCached(serviceId, url, InfoItem.InfoType.STREAM)) {
|
2019-08-07 12:00:47 +02:00
|
|
|
contentRootLayoutHiding.setVisibility(View.INVISIBLE);
|
|
|
|
}
|
|
|
|
|
2017-09-03 08:04:18 +02:00
|
|
|
animateView(thumbnailPlayButton, false, 50);
|
2018-03-10 17:16:51 +01:00
|
|
|
animateView(detailDurationView, false, 100);
|
2019-04-13 09:31:32 +02:00
|
|
|
animateView(detailPositionView, false, 100);
|
|
|
|
animateView(positionView, false, 50);
|
2017-03-31 20:15:26 +02:00
|
|
|
|
2020-10-18 20:19:50 +02:00
|
|
|
videoTitleTextView.setText(title);
|
2017-09-03 08:04:18 +02:00
|
|
|
videoTitleTextView.setMaxLines(1);
|
|
|
|
animateView(videoTitleTextView, true, 0);
|
2017-04-26 21:32:04 +02:00
|
|
|
|
2017-09-03 08:04:18 +02:00
|
|
|
videoDescriptionRootLayout.setVisibility(View.GONE);
|
2018-12-08 22:51:55 +01:00
|
|
|
videoTitleToggleArrow.setVisibility(View.GONE);
|
2017-09-03 08:04:18 +02:00
|
|
|
videoTitleRoot.setClickable(false);
|
2017-03-31 20:15:26 +02:00
|
|
|
|
2020-07-12 02:59:47 +02:00
|
|
|
if (relatedStreamsLayout != null) {
|
|
|
|
if (showRelatedStreams) {
|
2020-07-14 19:21:32 +02:00
|
|
|
relatedStreamsLayout.setVisibility(
|
|
|
|
player != null && player.isFullscreen() ? View.GONE : View.INVISIBLE);
|
2020-07-12 02:59:47 +02:00
|
|
|
} else {
|
2018-12-08 22:51:55 +01:00
|
|
|
relatedStreamsLayout.setVisibility(View.GONE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-31 19:20:15 +02:00
|
|
|
IMAGE_LOADER.cancelDisplayTask(thumbnailImageView);
|
2020-04-16 17:35:42 +02:00
|
|
|
IMAGE_LOADER.cancelDisplayTask(subChannelThumb);
|
2017-09-03 08:04:18 +02:00
|
|
|
thumbnailImageView.setImageBitmap(null);
|
2020-04-16 17:35:42 +02:00
|
|
|
subChannelThumb.setImageBitmap(null);
|
2017-03-31 20:15:26 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2020-03-31 19:20:15 +02:00
|
|
|
public void handleResult(@NonNull final StreamInfo info) {
|
2017-09-03 08:04:18 +02:00
|
|
|
super.handleResult(info);
|
2017-04-26 21:32:04 +02:00
|
|
|
|
2019-12-29 22:15:01 +01:00
|
|
|
currentInfo = info;
|
2020-01-10 15:32:05 +01:00
|
|
|
setInitialData(info.getServiceId(), info.getOriginalUrl(), info.getName(), playQueue);
|
2019-12-29 22:15:01 +01:00
|
|
|
|
2020-07-12 02:59:47 +02:00
|
|
|
if (showRelatedStreams) {
|
|
|
|
if (null == relatedStreamsLayout) { //phone
|
2020-03-31 19:20:15 +02:00
|
|
|
pageAdapter.updateItem(RELATED_TAB_TAG,
|
2020-07-13 03:17:21 +02:00
|
|
|
RelatedVideosFragment.getInstance(info));
|
2018-12-08 22:51:55 +01:00
|
|
|
pageAdapter.notifyDataSetUpdate();
|
2020-07-12 02:59:47 +02:00
|
|
|
} else { //tablet
|
2018-12-08 22:51:55 +01:00
|
|
|
getChildFragmentManager().beginTransaction()
|
2020-03-31 19:20:15 +02:00
|
|
|
.replace(R.id.relatedStreamsLayout,
|
2020-07-13 03:17:21 +02:00
|
|
|
RelatedVideosFragment.getInstance(info))
|
2020-07-16 00:15:24 +02:00
|
|
|
.commitAllowingStateLoss();
|
2020-07-14 19:21:32 +02:00
|
|
|
relatedStreamsLayout.setVisibility(
|
|
|
|
player != null && player.isFullscreen() ? View.GONE : View.VISIBLE);
|
2018-12-08 22:51:55 +01:00
|
|
|
}
|
2018-10-02 17:09:16 +02:00
|
|
|
}
|
2017-09-03 08:04:18 +02:00
|
|
|
animateView(thumbnailPlayButton, true, 200);
|
2020-10-18 20:19:50 +02:00
|
|
|
videoTitleTextView.setText(title);
|
2017-03-31 20:15:26 +02:00
|
|
|
|
2020-12-15 17:41:21 +01:00
|
|
|
if (!isEmpty(info.getSubChannelName())) {
|
2020-04-16 17:35:42 +02:00
|
|
|
displayBothUploaderAndSubChannel(info);
|
2020-12-15 17:41:21 +01:00
|
|
|
} else if (!isEmpty(info.getUploaderName())) {
|
2020-04-16 17:35:42 +02:00
|
|
|
displayUploaderAsSubChannel(info);
|
2017-12-08 15:05:08 +01:00
|
|
|
} else {
|
|
|
|
uploaderTextView.setVisibility(View.GONE);
|
2020-04-13 22:40:44 +02:00
|
|
|
uploaderThumb.setVisibility(View.GONE);
|
2017-12-08 15:05:08 +01:00
|
|
|
}
|
2020-04-13 22:40:44 +02:00
|
|
|
|
2020-08-16 10:24:58 +02:00
|
|
|
final Drawable buddyDrawable = AppCompatResources.getDrawable(activity, R.drawable.buddy);
|
2020-04-02 08:25:47 +02:00
|
|
|
subChannelThumb.setImageDrawable(buddyDrawable);
|
|
|
|
uploaderThumb.setImageDrawable(buddyDrawable);
|
2017-03-31 20:15:26 +02:00
|
|
|
|
2017-12-08 15:05:08 +01:00
|
|
|
if (info.getViewCount() >= 0) {
|
2019-10-28 03:37:36 +01:00
|
|
|
if (info.getStreamType().equals(StreamType.AUDIO_LIVE_STREAM)) {
|
|
|
|
videoCountView.setText(Localization.listeningCount(activity, info.getViewCount()));
|
|
|
|
} else if (info.getStreamType().equals(StreamType.LIVE_STREAM)) {
|
2020-03-31 19:20:15 +02:00
|
|
|
videoCountView.setText(Localization
|
|
|
|
.localizeWatchingCount(activity, info.getViewCount()));
|
2019-10-28 03:37:36 +01:00
|
|
|
} else {
|
2020-03-31 19:20:15 +02:00
|
|
|
videoCountView.setText(Localization
|
|
|
|
.localizeViewCount(activity, info.getViewCount()));
|
2019-10-28 03:37:36 +01:00
|
|
|
}
|
2017-12-08 15:05:08 +01:00
|
|
|
videoCountView.setVisibility(View.VISIBLE);
|
|
|
|
} else {
|
|
|
|
videoCountView.setVisibility(View.GONE);
|
|
|
|
}
|
2017-03-31 20:15:26 +02:00
|
|
|
|
2017-12-08 15:05:08 +01:00
|
|
|
if (info.getDislikeCount() == -1 && info.getLikeCount() == -1) {
|
2017-09-03 08:04:18 +02:00
|
|
|
thumbsDownImageView.setVisibility(View.VISIBLE);
|
|
|
|
thumbsUpImageView.setVisibility(View.VISIBLE);
|
|
|
|
thumbsUpTextView.setVisibility(View.GONE);
|
|
|
|
thumbsDownTextView.setVisibility(View.GONE);
|
2017-04-12 08:07:15 +02:00
|
|
|
|
2017-09-03 08:04:18 +02:00
|
|
|
thumbsDisabledTextView.setVisibility(View.VISIBLE);
|
|
|
|
} else {
|
2017-12-08 15:05:08 +01:00
|
|
|
if (info.getDislikeCount() >= 0) {
|
2020-03-31 19:20:15 +02:00
|
|
|
thumbsDownTextView.setText(Localization
|
|
|
|
.shortCount(activity, info.getDislikeCount()));
|
2017-12-08 15:05:08 +01:00
|
|
|
thumbsDownTextView.setVisibility(View.VISIBLE);
|
|
|
|
thumbsDownImageView.setVisibility(View.VISIBLE);
|
|
|
|
} else {
|
|
|
|
thumbsDownTextView.setVisibility(View.GONE);
|
|
|
|
thumbsDownImageView.setVisibility(View.GONE);
|
|
|
|
}
|
2017-06-28 03:39:33 +02:00
|
|
|
|
2017-12-08 15:05:08 +01:00
|
|
|
if (info.getLikeCount() >= 0) {
|
|
|
|
thumbsUpTextView.setText(Localization.shortCount(activity, info.getLikeCount()));
|
|
|
|
thumbsUpTextView.setVisibility(View.VISIBLE);
|
|
|
|
thumbsUpImageView.setVisibility(View.VISIBLE);
|
|
|
|
} else {
|
|
|
|
thumbsUpTextView.setVisibility(View.GONE);
|
|
|
|
thumbsUpImageView.setVisibility(View.GONE);
|
|
|
|
}
|
2017-09-03 08:04:18 +02:00
|
|
|
thumbsDisabledTextView.setVisibility(View.GONE);
|
|
|
|
}
|
2017-06-15 16:26:48 +02:00
|
|
|
|
2018-03-10 17:16:51 +01:00
|
|
|
if (info.getDuration() > 0) {
|
|
|
|
detailDurationView.setText(Localization.getDurationString(info.getDuration()));
|
2019-01-31 13:24:02 +01:00
|
|
|
detailDurationView.setBackgroundColor(
|
|
|
|
ContextCompat.getColor(activity, R.color.duration_background_color));
|
2018-03-10 17:16:51 +01:00
|
|
|
animateView(detailDurationView, true, 100);
|
|
|
|
} else if (info.getStreamType() == StreamType.LIVE_STREAM) {
|
|
|
|
detailDurationView.setText(R.string.duration_live);
|
2019-01-31 13:24:02 +01:00
|
|
|
detailDurationView.setBackgroundColor(
|
|
|
|
ContextCompat.getColor(activity, R.color.live_duration_background_color));
|
2018-03-10 17:16:51 +01:00
|
|
|
animateView(detailDurationView, true, 100);
|
|
|
|
} else {
|
|
|
|
detailDurationView.setVisibility(View.GONE);
|
|
|
|
}
|
|
|
|
|
2017-09-03 08:04:18 +02:00
|
|
|
videoDescriptionView.setVisibility(View.GONE);
|
2018-12-08 22:51:55 +01:00
|
|
|
videoTitleRoot.setClickable(true);
|
2020-04-01 21:41:56 +02:00
|
|
|
videoTitleToggleArrow.setImageResource(
|
|
|
|
ThemeHelper.resolveResourceIdFromAttr(requireContext(), R.attr.ic_expand_more));
|
2018-12-08 22:51:55 +01:00
|
|
|
videoTitleToggleArrow.setVisibility(View.VISIBLE);
|
|
|
|
videoDescriptionRootLayout.setVisibility(View.GONE);
|
2019-10-28 03:35:51 +01:00
|
|
|
|
|
|
|
if (info.getUploadDate() != null) {
|
2020-03-31 19:20:15 +02:00
|
|
|
videoUploadDateView.setText(Localization
|
2020-10-18 08:16:55 +02:00
|
|
|
.localizeUploadDate(activity, info.getUploadDate().offsetDateTime()));
|
2019-10-28 03:35:51 +01:00
|
|
|
videoUploadDateView.setVisibility(View.VISIBLE);
|
|
|
|
} else {
|
|
|
|
videoUploadDateView.setText(null);
|
|
|
|
videoUploadDateView.setVisibility(View.GONE);
|
2017-06-15 16:26:48 +02:00
|
|
|
}
|
2019-10-28 03:35:51 +01:00
|
|
|
|
2020-07-12 02:59:47 +02:00
|
|
|
sortedVideoStreams = ListHelper.getSortedStreamVideosList(
|
|
|
|
activity,
|
|
|
|
info.getVideoStreams(),
|
|
|
|
info.getVideoOnlyStreams(),
|
|
|
|
false);
|
2020-07-14 19:21:32 +02:00
|
|
|
selectedVideoStreamIndex = ListHelper
|
|
|
|
.getDefaultResolutionIndex(activity, sortedVideoStreams);
|
2017-12-08 15:05:08 +01:00
|
|
|
prepareDescription(info.getDescription());
|
2019-04-13 09:31:32 +02:00
|
|
|
updateProgressInfo(info);
|
2017-09-03 08:04:18 +02:00
|
|
|
initThumbnailViews(info);
|
2020-12-20 15:05:37 +01:00
|
|
|
showMetaInfoInTextView(info.getMetaInfo(), detailMetaInfoTextView, detailMetaInfoSeparator);
|
2020-12-15 17:41:21 +01:00
|
|
|
|
2018-04-06 09:35:44 +02:00
|
|
|
|
2021-01-08 18:35:33 +01:00
|
|
|
if (player == null || player.isStopped()) {
|
2020-02-05 06:59:30 +01:00
|
|
|
updateOverlayData(info.getName(), info.getUploaderName(), info.getThumbnailUrl());
|
2020-07-14 19:21:32 +02:00
|
|
|
}
|
2017-06-15 16:26:48 +02:00
|
|
|
|
2017-12-08 15:05:08 +01:00
|
|
|
if (!info.getErrors().isEmpty()) {
|
2018-02-16 11:31:25 +01:00
|
|
|
showSnackBarError(info.getErrors(),
|
|
|
|
UserAction.REQUESTED_STREAM,
|
|
|
|
NewPipe.getNameOfService(info.getServiceId()),
|
|
|
|
info.getUrl(),
|
|
|
|
0);
|
2017-06-15 16:26:48 +02:00
|
|
|
}
|
|
|
|
|
2020-10-02 16:03:43 +02:00
|
|
|
detailControlsDownload.setVisibility(info.getStreamType() == StreamType.LIVE_STREAM
|
|
|
|
|| info.getStreamType() == StreamType.AUDIO_LIVE_STREAM ? View.GONE : View.VISIBLE);
|
|
|
|
detailControlsBackground.setVisibility(info.getAudioStreams().isEmpty()
|
|
|
|
? View.GONE : View.VISIBLE);
|
|
|
|
|
|
|
|
final boolean noVideoStreams =
|
|
|
|
info.getVideoStreams().isEmpty() && info.getVideoOnlyStreams().isEmpty();
|
|
|
|
detailControlsPopup.setVisibility(noVideoStreams ? View.GONE : View.VISIBLE);
|
|
|
|
thumbnailPlayButton.setImageResource(
|
|
|
|
noVideoStreams ? R.drawable.ic_headset_shadow : R.drawable.ic_play_arrow_shadow);
|
2017-06-15 16:26:48 +02:00
|
|
|
}
|
|
|
|
|
2020-04-11 09:30:12 +02:00
|
|
|
private void hideAgeRestrictedContent() {
|
2020-09-29 21:09:11 +02:00
|
|
|
showError(getString(R.string.restricted_video,
|
|
|
|
getString(R.string.show_age_restricted_content_title)), false);
|
2020-04-11 09:30:12 +02:00
|
|
|
|
|
|
|
if (relatedStreamsLayout != null) { // tablet
|
|
|
|
relatedStreamsLayout.setVisibility(View.INVISIBLE);
|
|
|
|
}
|
|
|
|
|
|
|
|
viewPager.setVisibility(View.GONE);
|
|
|
|
tabLayout.setVisibility(View.GONE);
|
|
|
|
}
|
2018-04-07 19:32:02 +02:00
|
|
|
|
2020-04-16 17:35:42 +02:00
|
|
|
private void displayUploaderAsSubChannel(final StreamInfo info) {
|
|
|
|
subChannelTextView.setText(info.getUploaderName());
|
|
|
|
subChannelTextView.setVisibility(View.VISIBLE);
|
|
|
|
subChannelTextView.setSelected(true);
|
2020-04-13 22:40:44 +02:00
|
|
|
uploaderTextView.setVisibility(View.GONE);
|
|
|
|
}
|
|
|
|
|
2020-04-16 17:35:42 +02:00
|
|
|
private void displayBothUploaderAndSubChannel(final StreamInfo info) {
|
|
|
|
subChannelTextView.setText(info.getSubChannelName());
|
|
|
|
subChannelTextView.setVisibility(View.VISIBLE);
|
|
|
|
subChannelTextView.setSelected(true);
|
2020-04-13 22:40:44 +02:00
|
|
|
|
2020-05-07 20:51:54 +02:00
|
|
|
subChannelThumb.setVisibility(View.VISIBLE);
|
|
|
|
|
2020-12-15 17:41:21 +01:00
|
|
|
if (!isEmpty(info.getUploaderName())) {
|
2020-04-16 17:35:42 +02:00
|
|
|
uploaderTextView.setText(
|
|
|
|
String.format(getString(R.string.video_detail_by), info.getUploaderName()));
|
2020-04-13 22:40:44 +02:00
|
|
|
uploaderTextView.setVisibility(View.VISIBLE);
|
|
|
|
uploaderTextView.setSelected(true);
|
|
|
|
} else {
|
|
|
|
uploaderTextView.setVisibility(View.GONE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-07 19:32:02 +02:00
|
|
|
|
|
|
|
public void openDownloadDialog() {
|
2020-07-12 02:59:47 +02:00
|
|
|
try {
|
|
|
|
final DownloadDialog downloadDialog = DownloadDialog.newInstance(currentInfo);
|
|
|
|
downloadDialog.setVideoStreams(sortedVideoStreams);
|
|
|
|
downloadDialog.setAudioStreams(currentInfo.getAudioStreams());
|
|
|
|
downloadDialog.setSelectedVideoStream(selectedVideoStreamIndex);
|
|
|
|
downloadDialog.setSubtitleStreams(currentInfo.getSubtitles());
|
|
|
|
|
|
|
|
downloadDialog.show(activity.getSupportFragmentManager(), "downloadDialog");
|
2020-08-16 10:24:58 +02:00
|
|
|
} catch (final Exception e) {
|
2020-10-04 03:50:28 +02:00
|
|
|
final ErrorInfo info = ErrorInfo.make(UserAction.UI_ERROR,
|
2020-07-12 02:59:47 +02:00
|
|
|
ServiceList.all()
|
|
|
|
.get(currentInfo
|
|
|
|
.getServiceId())
|
|
|
|
.getServiceInfo()
|
|
|
|
.getName(), "",
|
|
|
|
R.string.could_not_setup_download_menu);
|
|
|
|
|
|
|
|
ErrorActivity.reportError(activity,
|
|
|
|
e,
|
|
|
|
activity.getClass(),
|
|
|
|
activity.findViewById(android.R.id.content), info);
|
|
|
|
}
|
2018-04-07 19:32:02 +02:00
|
|
|
}
|
|
|
|
|
2017-09-03 08:04:18 +02:00
|
|
|
/*//////////////////////////////////////////////////////////////////////////
|
|
|
|
// Stream Results
|
|
|
|
//////////////////////////////////////////////////////////////////////////*/
|
|
|
|
|
|
|
|
@Override
|
2020-03-31 19:20:15 +02:00
|
|
|
protected boolean onError(final Throwable exception) {
|
|
|
|
if (super.onError(exception)) {
|
|
|
|
return true;
|
2017-06-15 16:26:48 +02:00
|
|
|
}
|
2017-09-03 08:04:18 +02:00
|
|
|
|
2020-10-26 17:01:55 +01:00
|
|
|
final int errorId = exception instanceof YoutubeStreamExtractor.DeobfuscateException
|
|
|
|
? R.string.youtube_signature_deobfuscation_error
|
2020-03-31 19:20:15 +02:00
|
|
|
: exception instanceof ExtractionException
|
2020-07-14 19:21:32 +02:00
|
|
|
? R.string.parsing_error
|
|
|
|
: R.string.general_error;
|
2020-03-27 03:58:01 +01:00
|
|
|
|
|
|
|
onUnrecoverableError(exception, UserAction.REQUESTED_STREAM,
|
|
|
|
NewPipe.getNameOfService(serviceId), url, errorId);
|
2017-09-03 08:04:18 +02:00
|
|
|
|
|
|
|
return true;
|
2017-06-15 16:26:48 +02:00
|
|
|
}
|
2017-08-12 06:50:25 +02:00
|
|
|
|
2019-04-13 09:31:32 +02:00
|
|
|
private void updateProgressInfo(@NonNull final StreamInfo info) {
|
|
|
|
if (positionSubscriber != null) {
|
|
|
|
positionSubscriber.dispose();
|
|
|
|
}
|
|
|
|
final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(activity);
|
2020-03-31 19:20:15 +02:00
|
|
|
final boolean playbackResumeEnabled = prefs
|
|
|
|
.getBoolean(activity.getString(R.string.enable_watch_history_key), true)
|
|
|
|
&& prefs.getBoolean(activity.getString(R.string.enable_playback_resume_key), true);
|
2019-12-29 22:15:01 +01:00
|
|
|
final boolean showPlaybackPosition = prefs.getBoolean(
|
|
|
|
activity.getString(R.string.enable_playback_state_lists_key), true);
|
2020-03-10 10:06:38 +01:00
|
|
|
if (!playbackResumeEnabled) {
|
2019-12-29 22:15:01 +01:00
|
|
|
if (playQueue == null || playQueue.getStreams().isEmpty()
|
2020-07-14 19:21:32 +02:00
|
|
|
|| playQueue.getItem().getRecoveryPosition() == RECOVERY_UNSET
|
|
|
|
|| !showPlaybackPosition) {
|
2019-12-29 22:15:01 +01:00
|
|
|
positionView.setVisibility(View.INVISIBLE);
|
|
|
|
detailPositionView.setVisibility(View.GONE);
|
2020-07-13 03:17:21 +02:00
|
|
|
// TODO: Remove this check when separation of concerns is done.
|
|
|
|
// (live streams weren't getting updated because they are mixed)
|
|
|
|
if (!info.getStreamType().equals(StreamType.LIVE_STREAM)
|
|
|
|
&& !info.getStreamType().equals(StreamType.AUDIO_LIVE_STREAM)) {
|
|
|
|
return;
|
|
|
|
}
|
2019-12-29 22:15:01 +01:00
|
|
|
} else {
|
|
|
|
// Show saved position from backStack if user allows it
|
|
|
|
showPlaybackProgress(playQueue.getItem().getRecoveryPosition(),
|
|
|
|
playQueue.getItem().getDuration() * 1000);
|
|
|
|
animateView(positionView, true, 500);
|
|
|
|
animateView(detailPositionView, true, 500);
|
|
|
|
}
|
2020-07-14 19:21:32 +02:00
|
|
|
return;
|
|
|
|
}
|
2019-04-13 09:31:32 +02:00
|
|
|
final HistoryRecordManager recordManager = new HistoryRecordManager(requireContext());
|
2019-12-16 08:36:04 +01:00
|
|
|
|
|
|
|
// TODO: Separate concerns when updating database data.
|
|
|
|
// (move the updating part to when the loading happens)
|
2019-04-13 09:31:32 +02:00
|
|
|
positionSubscriber = recordManager.loadStreamState(info)
|
|
|
|
.subscribeOn(Schedulers.io())
|
|
|
|
.onErrorComplete()
|
|
|
|
.observeOn(AndroidSchedulers.mainThread())
|
|
|
|
.subscribe(state -> {
|
2019-12-29 22:15:01 +01:00
|
|
|
showPlaybackProgress(state.getProgressTime(), info.getDuration() * 1000);
|
2019-04-13 09:31:32 +02:00
|
|
|
animateView(positionView, true, 500);
|
|
|
|
animateView(detailPositionView, true, 500);
|
|
|
|
}, e -> {
|
2020-03-31 19:20:15 +02:00
|
|
|
if (DEBUG) {
|
|
|
|
e.printStackTrace();
|
|
|
|
}
|
2019-04-13 09:31:32 +02:00
|
|
|
}, () -> {
|
2020-06-27 05:25:50 +02:00
|
|
|
positionView.setVisibility(View.GONE);
|
|
|
|
detailPositionView.setVisibility(View.GONE);
|
2019-04-13 09:31:32 +02:00
|
|
|
});
|
2017-08-12 06:50:25 +02:00
|
|
|
}
|
2019-12-29 22:15:01 +01:00
|
|
|
|
2020-07-12 02:59:47 +02:00
|
|
|
private void showPlaybackProgress(final long progress, final long duration) {
|
2019-12-29 22:15:01 +01:00
|
|
|
final int progressSeconds = (int) TimeUnit.MILLISECONDS.toSeconds(progress);
|
|
|
|
final int durationSeconds = (int) TimeUnit.MILLISECONDS.toSeconds(duration);
|
2020-08-16 21:44:27 +02:00
|
|
|
// If the old and the new progress values have a big difference then use
|
|
|
|
// animation. Otherwise don't because it affects CPU
|
|
|
|
final boolean shouldAnimate = Math.abs(positionView.getProgress() - progressSeconds) > 2;
|
2019-12-29 22:15:01 +01:00
|
|
|
positionView.setMax(durationSeconds);
|
2020-08-16 21:44:27 +02:00
|
|
|
if (shouldAnimate) {
|
2020-08-05 11:46:25 +02:00
|
|
|
positionView.setProgressAnimated(progressSeconds);
|
|
|
|
} else {
|
|
|
|
positionView.setProgress(progressSeconds);
|
|
|
|
}
|
|
|
|
final String position = Localization.getDurationString(progressSeconds);
|
|
|
|
if (position != detailPositionView.getText()) {
|
|
|
|
detailPositionView.setText(position);
|
|
|
|
}
|
2020-03-10 10:06:38 +01:00
|
|
|
if (positionView.getVisibility() != View.VISIBLE) {
|
|
|
|
animateView(positionView, true, 100);
|
|
|
|
animateView(detailPositionView, true, 100);
|
|
|
|
}
|
2019-12-29 22:15:01 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/*//////////////////////////////////////////////////////////////////////////
|
|
|
|
// Player event listener
|
|
|
|
//////////////////////////////////////////////////////////////////////////*/
|
|
|
|
|
2020-01-06 11:39:01 +01:00
|
|
|
@Override
|
2020-07-12 02:59:47 +02:00
|
|
|
public void onQueueUpdate(final PlayQueue queue) {
|
2020-01-06 11:39:01 +01:00
|
|
|
playQueue = queue;
|
2020-10-18 09:50:42 +02:00
|
|
|
if (DEBUG) {
|
|
|
|
Log.d(TAG, "onQueueUpdate() called with: serviceId = ["
|
|
|
|
+ serviceId + "], videoUrl = [" + url + "], name = ["
|
2020-10-18 20:19:50 +02:00
|
|
|
+ title + "], playQueue = [" + playQueue + "]");
|
2020-10-18 09:50:42 +02:00
|
|
|
}
|
|
|
|
|
2020-07-14 19:21:32 +02:00
|
|
|
// This should be the only place where we push data to stack.
|
|
|
|
// It will allow to have live instance of PlayQueue with actual information about
|
|
|
|
// deleted/added items inside Channel/Playlist queue and makes possible to have
|
|
|
|
// a history of played items
|
2020-10-18 09:50:42 +02:00
|
|
|
@Nullable final StackItem stackPeek = stack.peek();
|
2020-11-13 21:39:27 +01:00
|
|
|
if (stackPeek != null && !stackPeek.getPlayQueue().equals(queue)) {
|
2020-10-18 09:50:42 +02:00
|
|
|
@Nullable final PlayQueueItem playQueueItem = queue.getItem();
|
|
|
|
if (playQueueItem != null) {
|
|
|
|
stack.push(new StackItem(playQueueItem.getServiceId(), playQueueItem.getUrl(),
|
|
|
|
playQueueItem.getTitle(), queue));
|
|
|
|
return;
|
|
|
|
} // else continue below
|
2020-02-29 00:57:54 +01:00
|
|
|
}
|
2020-01-06 11:39:01 +01:00
|
|
|
|
2020-10-18 09:50:42 +02:00
|
|
|
@Nullable final StackItem stackWithQueue = findQueueInStack(queue);
|
|
|
|
if (stackWithQueue != null) {
|
|
|
|
// On every MainPlayer service's destroy() playQueue gets disposed and
|
|
|
|
// no longer able to track progress. That's why we update our cached disposed
|
|
|
|
// queue with the new one that is active and have the same history.
|
|
|
|
// Without that the cached playQueue will have an old recovery position
|
|
|
|
stackWithQueue.setPlayQueue(queue);
|
2020-01-06 11:39:01 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-12-29 22:15:01 +01:00
|
|
|
@Override
|
2020-07-14 19:21:32 +02:00
|
|
|
public void onPlaybackUpdate(final int state,
|
|
|
|
final int repeatMode,
|
|
|
|
final boolean shuffled,
|
|
|
|
final PlaybackParameters parameters) {
|
2020-09-29 05:22:53 +02:00
|
|
|
setOverlayPlayPauseImage(player != null && player.isPlaying());
|
2019-12-29 22:15:01 +01:00
|
|
|
|
|
|
|
switch (state) {
|
2021-01-08 18:35:33 +01:00
|
|
|
case Player.STATE_PLAYING:
|
2020-06-27 05:25:50 +02:00
|
|
|
if (positionView.getAlpha() != 1.0f
|
2020-01-10 15:32:05 +01:00
|
|
|
&& player.getPlayQueue() != null
|
|
|
|
&& player.getPlayQueue().getItem() != null
|
|
|
|
&& player.getPlayQueue().getItem().getUrl().equals(url)) {
|
|
|
|
animateView(positionView, true, 100);
|
|
|
|
animateView(detailPositionView, true, 100);
|
|
|
|
}
|
2019-12-29 22:15:01 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2020-07-14 19:21:32 +02:00
|
|
|
public void onProgressUpdate(final int currentProgress,
|
|
|
|
final int duration,
|
|
|
|
final int bufferPercent) {
|
2019-12-29 22:15:01 +01:00
|
|
|
// Progress updates every second even if media is paused. It's useless until playing
|
2021-01-08 18:35:33 +01:00
|
|
|
if (!player.isPlaying() || playQueue == null) {
|
2020-07-14 19:21:32 +02:00
|
|
|
return;
|
|
|
|
}
|
2020-01-09 16:28:06 +01:00
|
|
|
|
2020-07-14 19:21:32 +02:00
|
|
|
if (player.getPlayQueue().getItem().getUrl().equals(url)) {
|
2020-01-10 15:32:05 +01:00
|
|
|
showPlaybackProgress(currentProgress, duration);
|
2020-07-14 19:21:32 +02:00
|
|
|
}
|
2019-12-29 22:15:01 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2020-07-12 02:59:47 +02:00
|
|
|
public void onMetadataUpdate(final StreamInfo info, final PlayQueue queue) {
|
|
|
|
final StackItem item = findQueueInStack(queue);
|
2020-03-10 10:06:38 +01:00
|
|
|
if (item != null) {
|
2020-07-14 19:21:32 +02:00
|
|
|
// When PlayQueue can have multiple streams (PlaylistPlayQueue or ChannelPlayQueue)
|
|
|
|
// every new played stream gives new title and url.
|
|
|
|
// StackItem contains information about first played stream. Let's update it here
|
2020-03-10 10:06:38 +01:00
|
|
|
item.setTitle(info.getName());
|
|
|
|
item.setUrl(info.getUrl());
|
2020-01-06 11:39:01 +01:00
|
|
|
}
|
2020-07-14 19:21:32 +02:00
|
|
|
// They are not equal when user watches something in popup while browsing in fragment and
|
|
|
|
// then changes screen orientation. In that case the fragment will set itself as
|
|
|
|
// a service listener and will receive initial call to onMetadataUpdate()
|
|
|
|
if (!queue.equals(playQueue)) {
|
|
|
|
return;
|
|
|
|
}
|
2020-01-06 11:39:01 +01:00
|
|
|
|
2020-02-05 06:59:30 +01:00
|
|
|
updateOverlayData(info.getName(), info.getUploaderName(), info.getThumbnailUrl());
|
2020-07-14 19:21:32 +02:00
|
|
|
if (currentInfo != null && info.getUrl().equals(currentInfo.getUrl())) {
|
|
|
|
return;
|
|
|
|
}
|
2019-12-29 22:15:01 +01:00
|
|
|
|
|
|
|
currentInfo = info;
|
2020-07-12 02:59:47 +02:00
|
|
|
setInitialData(info.getServiceId(), info.getUrl(), info.getName(), queue);
|
2020-10-18 20:19:50 +02:00
|
|
|
setAutoPlay(false);
|
2020-09-17 22:42:35 +02:00
|
|
|
// Delay execution just because it freezes the main thread, and while playing
|
|
|
|
// next/previous video you see visual glitches
|
|
|
|
// (when non-vertical video goes after vertical video)
|
|
|
|
prepareAndHandleInfoIfNeededAfterDelay(info, true, 200);
|
2019-12-29 22:15:01 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2020-07-12 02:59:47 +02:00
|
|
|
public void onPlayerError(final ExoPlaybackException error) {
|
2020-07-14 19:21:32 +02:00
|
|
|
if (error.type == ExoPlaybackException.TYPE_SOURCE
|
|
|
|
|| error.type == ExoPlaybackException.TYPE_UNEXPECTED) {
|
2020-09-17 18:01:20 +02:00
|
|
|
// Properly exit from fullscreen
|
2020-07-14 19:21:32 +02:00
|
|
|
if (playerService != null && player.isFullscreen()) {
|
2019-12-29 22:15:01 +01:00
|
|
|
player.toggleFullscreen();
|
2020-07-14 19:21:32 +02:00
|
|
|
}
|
2020-09-17 18:01:20 +02:00
|
|
|
hideMainPlayer();
|
2019-12-29 22:15:01 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onServiceStopped() {
|
2020-09-29 05:22:53 +02:00
|
|
|
setOverlayPlayPauseImage(false);
|
2020-07-14 19:21:32 +02:00
|
|
|
if (currentInfo != null) {
|
|
|
|
updateOverlayData(currentInfo.getName(),
|
|
|
|
currentInfo.getUploaderName(),
|
|
|
|
currentInfo.getThumbnailUrl());
|
|
|
|
}
|
2019-12-29 22:15:01 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2020-07-12 02:59:47 +02:00
|
|
|
public void onFullscreenStateChanged(final boolean fullscreen) {
|
2020-09-04 04:39:55 +02:00
|
|
|
setupBrightness();
|
2020-07-14 19:21:32 +02:00
|
|
|
if (playerService.getView() == null || player.getParentActivity() == null) {
|
2019-12-29 22:15:01 +01:00
|
|
|
return;
|
2020-07-14 19:21:32 +02:00
|
|
|
}
|
2019-12-29 22:15:01 +01:00
|
|
|
|
2020-07-12 02:59:47 +02:00
|
|
|
final View view = playerService.getView();
|
|
|
|
final ViewGroup parent = (ViewGroup) view.getParent();
|
2020-07-14 19:21:32 +02:00
|
|
|
if (parent == null) {
|
|
|
|
return;
|
|
|
|
}
|
2019-12-29 22:15:01 +01:00
|
|
|
|
|
|
|
if (fullscreen) {
|
2020-02-29 00:57:54 +01:00
|
|
|
hideSystemUiIfNeeded();
|
2019-12-29 22:15:01 +01:00
|
|
|
} else {
|
|
|
|
showSystemUi();
|
|
|
|
}
|
|
|
|
|
2020-07-14 19:21:32 +02:00
|
|
|
if (relatedStreamsLayout != null) {
|
|
|
|
relatedStreamsLayout.setVisibility(fullscreen ? View.GONE : View.VISIBLE);
|
|
|
|
}
|
2020-02-25 00:15:22 +01:00
|
|
|
scrollToTop();
|
2019-12-29 22:15:01 +01:00
|
|
|
|
2020-09-27 03:25:06 +02:00
|
|
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
|
|
|
addVideoPlayerView();
|
|
|
|
} else {
|
|
|
|
// KitKat needs a delay before addVideoPlayerView call or it reports wrong height in
|
|
|
|
// activity.getWindow().getDecorView().getHeight()
|
|
|
|
new Handler().post(this::addVideoPlayerView);
|
|
|
|
}
|
2019-12-29 22:15:01 +01:00
|
|
|
}
|
|
|
|
|
2020-01-16 12:20:22 +01:00
|
|
|
@Override
|
|
|
|
public void onScreenRotationButtonClicked() {
|
2020-07-14 19:21:32 +02:00
|
|
|
// In tablet user experience will be better if screen will not be rotated
|
|
|
|
// from landscape to portrait every time.
|
2020-01-17 15:37:53 +01:00
|
|
|
// Just turn on fullscreen mode in landscape orientation
|
2020-09-27 03:11:38 +02:00
|
|
|
// or portrait & unlocked global orientation
|
|
|
|
if (DeviceUtils.isTablet(activity)
|
|
|
|
&& (!globalScreenOrientationLocked(activity) || isLandscape())) {
|
2020-01-17 15:37:53 +01:00
|
|
|
player.toggleFullscreen();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-07-14 19:21:32 +02:00
|
|
|
final int newOrientation = isLandscape()
|
2020-09-27 03:11:38 +02:00
|
|
|
? ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
|
2020-01-16 12:20:22 +01:00
|
|
|
: ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE;
|
|
|
|
|
|
|
|
activity.setRequestedOrientation(newOrientation);
|
|
|
|
}
|
|
|
|
|
2019-12-29 22:15:01 +01:00
|
|
|
/*
|
2020-07-12 02:59:47 +02:00
|
|
|
* Will scroll down to description view after long click on moreOptionsButton
|
|
|
|
* */
|
2019-12-29 22:15:01 +01:00
|
|
|
@Override
|
|
|
|
public void onMoreOptionsLongClicked() {
|
2020-07-14 19:21:32 +02:00
|
|
|
final CoordinatorLayout.LayoutParams params =
|
|
|
|
(CoordinatorLayout.LayoutParams) appBarLayout.getLayoutParams();
|
2020-07-12 02:59:47 +02:00
|
|
|
final AppBarLayout.Behavior behavior = (AppBarLayout.Behavior) params.getBehavior();
|
2020-07-14 19:21:32 +02:00
|
|
|
final ValueAnimator valueAnimator = ValueAnimator
|
2020-08-05 11:46:25 +02:00
|
|
|
.ofInt(0, -playerPlaceholder.getHeight());
|
2019-12-29 22:15:01 +01:00
|
|
|
valueAnimator.setInterpolator(new DecelerateInterpolator());
|
|
|
|
valueAnimator.addUpdateListener(animation -> {
|
|
|
|
behavior.setTopAndBottomOffset((int) animation.getAnimatedValue());
|
|
|
|
appBarLayout.requestLayout();
|
|
|
|
});
|
|
|
|
valueAnimator.setInterpolator(new DecelerateInterpolator());
|
|
|
|
valueAnimator.setDuration(500);
|
|
|
|
valueAnimator.start();
|
|
|
|
}
|
|
|
|
|
|
|
|
/*//////////////////////////////////////////////////////////////////////////
|
|
|
|
// Player related utils
|
|
|
|
//////////////////////////////////////////////////////////////////////////*/
|
|
|
|
|
|
|
|
private void showSystemUi() {
|
2020-07-14 19:21:32 +02:00
|
|
|
if (DEBUG) {
|
|
|
|
Log.d(TAG, "showSystemUi() called");
|
|
|
|
}
|
2019-12-29 22:15:01 +01:00
|
|
|
|
2020-07-14 19:21:32 +02:00
|
|
|
if (activity == null) {
|
|
|
|
return;
|
|
|
|
}
|
2020-01-08 17:16:50 +01:00
|
|
|
|
2020-08-17 16:42:32 +02:00
|
|
|
// Prevent jumping of the player on devices with cutout
|
|
|
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
|
|
|
activity.getWindow().getAttributes().layoutInDisplayCutoutMode =
|
|
|
|
WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT;
|
|
|
|
}
|
2020-01-08 17:16:50 +01:00
|
|
|
activity.getWindow().getDecorView().setSystemUiVisibility(0);
|
2020-09-15 13:43:43 +02:00
|
|
|
activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
|
|
|
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
2020-09-14 10:30:41 +02:00
|
|
|
activity.getWindow().setStatusBarColor(ThemeHelper.resolveColorFromAttr(
|
|
|
|
requireContext(), android.R.attr.colorPrimary));
|
|
|
|
}
|
2019-12-29 22:15:01 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
private void hideSystemUi() {
|
2020-07-14 19:21:32 +02:00
|
|
|
if (DEBUG) {
|
|
|
|
Log.d(TAG, "hideSystemUi() called");
|
|
|
|
}
|
2019-12-29 22:15:01 +01:00
|
|
|
|
2020-07-14 19:21:32 +02:00
|
|
|
if (activity == null) {
|
|
|
|
return;
|
|
|
|
}
|
2020-01-08 17:16:50 +01:00
|
|
|
|
2020-08-17 16:42:32 +02:00
|
|
|
// Prevent jumping of the player on devices with cutout
|
|
|
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
|
|
|
activity.getWindow().getAttributes().layoutInDisplayCutoutMode =
|
2020-09-15 13:43:43 +02:00
|
|
|
WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
|
2020-08-17 16:42:32 +02:00
|
|
|
}
|
2020-09-15 13:43:43 +02:00
|
|
|
int visibility = View.SYSTEM_UI_FLAG_LAYOUT_STABLE
|
2020-01-03 06:05:31 +01:00
|
|
|
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
|
|
|
|
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
|
|
|
|
| View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
|
|
|
|
| View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
|
2020-09-15 13:43:43 +02:00
|
|
|
// In multiWindow mode status bar is not transparent for devices with cutout
|
|
|
|
// if I include this flag. So without it is better in this case
|
|
|
|
if (!isInMultiWindow()) {
|
|
|
|
visibility |= View.SYSTEM_UI_FLAG_FULLSCREEN;
|
|
|
|
}
|
2020-01-03 06:05:31 +01:00
|
|
|
activity.getWindow().getDecorView().setSystemUiVisibility(visibility);
|
2020-09-15 13:43:43 +02:00
|
|
|
|
|
|
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP
|
|
|
|
&& (isInMultiWindow() || (player != null && player.isFullscreen()))) {
|
|
|
|
activity.getWindow().setStatusBarColor(Color.TRANSPARENT);
|
2020-09-15 18:50:46 +02:00
|
|
|
activity.getWindow().setNavigationBarColor(Color.TRANSPARENT);
|
2020-09-15 13:43:43 +02:00
|
|
|
}
|
|
|
|
activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
|
2019-12-29 22:15:01 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// Listener implementation
|
2020-02-29 00:57:54 +01:00
|
|
|
public void hideSystemUiIfNeeded() {
|
2020-07-14 19:21:32 +02:00
|
|
|
if (player != null
|
|
|
|
&& player.isFullscreen()
|
|
|
|
&& bottomSheetBehavior.getState() == BottomSheetBehavior.STATE_EXPANDED) {
|
2019-12-29 22:15:01 +01:00
|
|
|
hideSystemUi();
|
2020-07-14 19:21:32 +02:00
|
|
|
}
|
2019-12-29 22:15:01 +01:00
|
|
|
}
|
|
|
|
|
2020-02-29 00:57:54 +01:00
|
|
|
private boolean playerIsNotStopped() {
|
2021-01-08 18:35:33 +01:00
|
|
|
return player != null && !player.isStopped();
|
2020-02-29 00:57:54 +01:00
|
|
|
}
|
|
|
|
|
2020-09-11 19:52:38 +02:00
|
|
|
private void restoreDefaultBrightness() {
|
2020-09-04 04:39:55 +02:00
|
|
|
final WindowManager.LayoutParams lp = activity.getWindow().getAttributes();
|
|
|
|
if (lp.screenBrightness == -1) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Restore the old brightness when fragment.onPause() called or
|
|
|
|
// when a player is in portrait
|
|
|
|
lp.screenBrightness = -1;
|
|
|
|
activity.getWindow().setAttributes(lp);
|
|
|
|
}
|
|
|
|
|
|
|
|
private void setupBrightness() {
|
2020-07-14 19:21:32 +02:00
|
|
|
if (activity == null) {
|
|
|
|
return;
|
|
|
|
}
|
2020-01-08 17:16:50 +01:00
|
|
|
|
2020-07-12 02:59:47 +02:00
|
|
|
final WindowManager.LayoutParams lp = activity.getWindow().getAttributes();
|
2020-09-04 04:39:55 +02:00
|
|
|
if (player == null
|
|
|
|
|| !player.videoPlayerSelected()
|
|
|
|
|| !player.isFullscreen()
|
|
|
|
|| bottomSheetState != BottomSheetBehavior.STATE_EXPANDED) {
|
|
|
|
// Apply system brightness when the player is not in fullscreen
|
2020-09-11 19:52:38 +02:00
|
|
|
restoreDefaultBrightness();
|
2019-12-29 22:15:01 +01:00
|
|
|
} else {
|
2020-12-26 18:47:08 +01:00
|
|
|
// Do not restore if user has disabled brightness gesture
|
|
|
|
if (!PlayerHelper.isBrightnessGestureEnabled(activity)) {
|
|
|
|
return;
|
|
|
|
}
|
2019-12-29 22:15:01 +01:00
|
|
|
// Restore already saved brightness level
|
2020-07-12 02:59:47 +02:00
|
|
|
final float brightnessLevel = PlayerHelper.getScreenBrightness(activity);
|
2020-09-04 04:39:55 +02:00
|
|
|
if (brightnessLevel == lp.screenBrightness) {
|
2019-12-29 22:15:01 +01:00
|
|
|
return;
|
2020-07-14 19:21:32 +02:00
|
|
|
}
|
2019-12-29 22:15:01 +01:00
|
|
|
lp.screenBrightness = brightnessLevel;
|
2020-09-04 04:39:55 +02:00
|
|
|
activity.getWindow().setAttributes(lp);
|
2019-12-29 22:15:01 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private void checkLandscape() {
|
2020-07-14 19:21:32 +02:00
|
|
|
if ((!player.isPlaying() && player.getPlayQueue() != playQueue)
|
|
|
|
|| player.getPlayQueue() == null) {
|
2020-10-18 20:19:50 +02:00
|
|
|
setAutoPlay(true);
|
2020-07-14 19:21:32 +02:00
|
|
|
}
|
2019-12-29 22:15:01 +01:00
|
|
|
|
2020-02-25 00:15:22 +01:00
|
|
|
player.checkLandscape();
|
2019-12-29 22:15:01 +01:00
|
|
|
// Let's give a user time to look at video information page if video is not playing
|
2020-09-27 03:11:38 +02:00
|
|
|
if (globalScreenOrientationLocked(activity) && !player.isPlaying()) {
|
2021-01-08 18:35:33 +01:00
|
|
|
player.play();
|
2020-01-16 12:20:22 +01:00
|
|
|
}
|
2019-12-29 22:15:01 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
private boolean isLandscape() {
|
2020-07-14 19:21:32 +02:00
|
|
|
return getResources().getDisplayMetrics().heightPixels < getResources()
|
|
|
|
.getDisplayMetrics().widthPixels;
|
2019-12-29 22:15:01 +01:00
|
|
|
}
|
|
|
|
|
2020-01-03 06:05:31 +01:00
|
|
|
private boolean isInMultiWindow() {
|
|
|
|
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && activity.isInMultiWindowMode();
|
|
|
|
}
|
|
|
|
|
2019-12-29 22:15:01 +01:00
|
|
|
/*
|
2020-07-14 19:21:32 +02:00
|
|
|
* Means that the player fragment was swiped away via BottomSheetLayout
|
|
|
|
* and is empty but ready for any new actions. See cleanUp()
|
2020-07-12 02:59:47 +02:00
|
|
|
* */
|
2019-12-29 22:15:01 +01:00
|
|
|
private boolean wasCleared() {
|
|
|
|
return url == null;
|
|
|
|
}
|
|
|
|
|
2020-10-18 09:50:42 +02:00
|
|
|
@Nullable
|
2020-07-12 02:59:47 +02:00
|
|
|
private StackItem findQueueInStack(final PlayQueue queue) {
|
2020-03-10 10:06:38 +01:00
|
|
|
StackItem item = null;
|
2020-07-12 02:59:47 +02:00
|
|
|
final Iterator<StackItem> iterator = stack.descendingIterator();
|
2020-03-10 10:06:38 +01:00
|
|
|
while (iterator.hasNext()) {
|
2020-07-12 02:59:47 +02:00
|
|
|
final StackItem next = iterator.next();
|
2020-03-10 10:06:38 +01:00
|
|
|
if (next.getPlayQueue().equals(queue)) {
|
|
|
|
item = next;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return item;
|
|
|
|
}
|
|
|
|
|
2020-06-27 05:25:50 +02:00
|
|
|
private void replaceQueueIfUserConfirms(final Runnable onAllow) {
|
|
|
|
@Nullable final PlayQueue activeQueue = player == null ? null : player.getPlayQueue();
|
|
|
|
|
2020-03-10 10:06:38 +01:00
|
|
|
// Player will have STATE_IDLE when a user pressed back button
|
2020-06-27 05:25:50 +02:00
|
|
|
if (isClearingQueueConfirmationRequired(activity)
|
|
|
|
&& playerIsNotStopped()
|
|
|
|
&& activeQueue != null
|
2020-10-09 16:46:42 +02:00
|
|
|
&& !activeQueue.equals(playQueue)) {
|
2020-06-27 05:25:50 +02:00
|
|
|
showClearingQueueConfirmation(onAllow);
|
|
|
|
} else {
|
|
|
|
onAllow.run();
|
|
|
|
}
|
2020-03-10 10:06:38 +01:00
|
|
|
}
|
|
|
|
|
2020-07-12 02:59:47 +02:00
|
|
|
private void showClearingQueueConfirmation(final Runnable onAllow) {
|
2020-03-10 10:06:38 +01:00
|
|
|
new AlertDialog.Builder(activity)
|
2020-07-23 23:43:09 +02:00
|
|
|
.setTitle(R.string.clear_queue_confirmation_description)
|
2020-03-10 10:06:38 +01:00
|
|
|
.setNegativeButton(android.R.string.cancel, null)
|
|
|
|
.setPositiveButton(android.R.string.yes, (dialog, which) -> {
|
|
|
|
onAllow.run();
|
|
|
|
dialog.dismiss();
|
|
|
|
}).show();
|
|
|
|
}
|
|
|
|
|
2020-07-23 23:43:09 +02:00
|
|
|
private void showExternalPlaybackDialog() {
|
|
|
|
if (sortedVideoStreams == null) {
|
|
|
|
return;
|
|
|
|
}
|
2020-08-16 10:24:58 +02:00
|
|
|
final CharSequence[] resolutions = new CharSequence[sortedVideoStreams.size()];
|
2020-07-23 23:43:09 +02:00
|
|
|
for (int i = 0; i < sortedVideoStreams.size(); i++) {
|
|
|
|
resolutions[i] = sortedVideoStreams.get(i).getResolution();
|
|
|
|
}
|
2020-08-16 10:24:58 +02:00
|
|
|
final AlertDialog.Builder builder = new AlertDialog.Builder(activity)
|
2020-07-23 23:43:09 +02:00
|
|
|
.setNegativeButton(android.R.string.cancel, null)
|
|
|
|
.setNeutralButton(R.string.open_in_browser, (dialog, i) ->
|
|
|
|
ShareUtils.openUrlInBrowser(requireActivity(), url)
|
|
|
|
);
|
|
|
|
// Maybe there are no video streams available, show just `open in browser` button
|
|
|
|
if (resolutions.length > 0) {
|
|
|
|
builder.setSingleChoiceItems(resolutions, selectedVideoStreamIndex, (dialog, i) -> {
|
|
|
|
dialog.dismiss();
|
|
|
|
startOnExternalPlayer(activity, currentInfo, sortedVideoStreams.get(i));
|
|
|
|
}
|
|
|
|
);
|
|
|
|
}
|
|
|
|
builder.show();
|
|
|
|
}
|
|
|
|
|
2019-12-29 22:15:01 +01:00
|
|
|
/*
|
2020-07-12 02:59:47 +02:00
|
|
|
* Remove unneeded information while waiting for a next task
|
|
|
|
* */
|
2019-12-29 22:15:01 +01:00
|
|
|
private void cleanUp() {
|
|
|
|
// New beginning
|
|
|
|
stack.clear();
|
2020-07-14 19:21:32 +02:00
|
|
|
if (currentWorker != null) {
|
|
|
|
currentWorker.dispose();
|
|
|
|
}
|
2020-09-17 22:42:35 +02:00
|
|
|
PlayerHolder.stopService(App.getApp());
|
2020-07-12 02:59:47 +02:00
|
|
|
setInitialData(0, null, "", null);
|
2019-12-29 22:15:01 +01:00
|
|
|
currentInfo = null;
|
2020-02-05 06:59:30 +01:00
|
|
|
updateOverlayData(null, null, null);
|
2019-12-29 22:15:01 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/*//////////////////////////////////////////////////////////////////////////
|
|
|
|
// Bottom mini player
|
|
|
|
//////////////////////////////////////////////////////////////////////////*/
|
|
|
|
|
2020-07-25 03:14:29 +02:00
|
|
|
/**
|
|
|
|
* That's for Android TV support. Move focus from main fragment to the player or back
|
|
|
|
* based on what is currently selected
|
2020-07-25 06:00:53 +02:00
|
|
|
*
|
2020-07-25 03:14:29 +02:00
|
|
|
* @param toMain if true than the main fragment will be focused or the player otherwise
|
2020-07-25 06:00:53 +02:00
|
|
|
*/
|
2020-07-25 03:14:29 +02:00
|
|
|
private void moveFocusToMainFragment(final boolean toMain) {
|
2020-09-04 04:39:55 +02:00
|
|
|
setupBrightness();
|
2020-07-25 03:14:29 +02:00
|
|
|
final ViewGroup mainFragment = requireActivity().findViewById(R.id.fragment_holder);
|
|
|
|
// Hamburger button steels a focus even under bottomSheet
|
|
|
|
final Toolbar toolbar = requireActivity().findViewById(R.id.toolbar);
|
|
|
|
final int afterDescendants = ViewGroup.FOCUS_AFTER_DESCENDANTS;
|
|
|
|
final int blockDescendants = ViewGroup.FOCUS_BLOCK_DESCENDANTS;
|
|
|
|
if (toMain) {
|
|
|
|
mainFragment.setDescendantFocusability(afterDescendants);
|
|
|
|
toolbar.setDescendantFocusability(afterDescendants);
|
|
|
|
((ViewGroup) requireView()).setDescendantFocusability(blockDescendants);
|
|
|
|
mainFragment.requestFocus();
|
|
|
|
} else {
|
|
|
|
mainFragment.setDescendantFocusability(blockDescendants);
|
|
|
|
toolbar.setDescendantFocusability(blockDescendants);
|
|
|
|
((ViewGroup) requireView()).setDescendantFocusability(afterDescendants);
|
|
|
|
thumbnailBackgroundButton.requestFocus();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-08-15 19:51:52 +02:00
|
|
|
/**
|
|
|
|
* 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
|
|
|
|
*
|
|
|
|
* @param showMore whether main fragment should be expanded or not
|
2020-09-04 04:39:55 +02:00
|
|
|
*/
|
2020-08-15 19:51:52 +02:00
|
|
|
private void manageSpaceAtTheBottom(final boolean showMore) {
|
|
|
|
final int peekHeight = getResources().getDimensionPixelSize(R.dimen.mini_player_height);
|
|
|
|
final ViewGroup holder = requireActivity().findViewById(R.id.fragment_holder);
|
|
|
|
final int newBottomPadding;
|
|
|
|
if (showMore) {
|
|
|
|
newBottomPadding = 0;
|
|
|
|
} else {
|
|
|
|
newBottomPadding = peekHeight;
|
|
|
|
}
|
|
|
|
if (holder.getPaddingBottom() == newBottomPadding) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
holder.setPadding(holder.getPaddingLeft(),
|
|
|
|
holder.getPaddingTop(),
|
|
|
|
holder.getPaddingRight(),
|
|
|
|
newBottomPadding);
|
|
|
|
}
|
|
|
|
|
2019-12-29 22:15:01 +01:00
|
|
|
private void setupBottomPlayer() {
|
2020-07-14 19:21:32 +02:00
|
|
|
final CoordinatorLayout.LayoutParams params =
|
|
|
|
(CoordinatorLayout.LayoutParams) appBarLayout.getLayoutParams();
|
2020-07-12 02:59:47 +02:00
|
|
|
final AppBarLayout.Behavior behavior = (AppBarLayout.Behavior) params.getBehavior();
|
2019-12-29 22:15:01 +01:00
|
|
|
|
2020-07-12 02:59:47 +02:00
|
|
|
final FrameLayout bottomSheetLayout = activity.findViewById(R.id.fragment_player_holder);
|
2019-12-29 22:15:01 +01:00
|
|
|
bottomSheetBehavior = BottomSheetBehavior.from(bottomSheetLayout);
|
|
|
|
bottomSheetBehavior.setState(bottomSheetState);
|
|
|
|
final int peekHeight = getResources().getDimensionPixelSize(R.dimen.mini_player_height);
|
|
|
|
if (bottomSheetState != BottomSheetBehavior.STATE_HIDDEN) {
|
2020-08-15 19:51:52 +02:00
|
|
|
manageSpaceAtTheBottom(false);
|
2019-12-29 22:15:01 +01:00
|
|
|
bottomSheetBehavior.setPeekHeight(peekHeight);
|
2020-01-17 15:37:53 +01:00
|
|
|
if (bottomSheetState == BottomSheetBehavior.STATE_COLLAPSED) {
|
|
|
|
overlay.setAlpha(MAX_OVERLAY_ALPHA);
|
|
|
|
} else if (bottomSheetState == BottomSheetBehavior.STATE_EXPANDED) {
|
|
|
|
overlay.setAlpha(0);
|
2019-12-29 22:15:01 +01:00
|
|
|
setOverlayElementsClickable(false);
|
2020-01-17 15:37:53 +01:00
|
|
|
}
|
2019-12-29 22:15:01 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
bottomSheetBehavior.setBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() {
|
2020-07-12 02:59:47 +02:00
|
|
|
@Override
|
|
|
|
public void onStateChanged(@NonNull final View bottomSheet, final int newState) {
|
2019-12-29 22:15:01 +01:00
|
|
|
bottomSheetState = newState;
|
2020-07-25 03:14:29 +02:00
|
|
|
|
2019-12-29 22:15:01 +01:00
|
|
|
switch (newState) {
|
|
|
|
case BottomSheetBehavior.STATE_HIDDEN:
|
2020-07-25 03:14:29 +02:00
|
|
|
moveFocusToMainFragment(true);
|
2020-08-15 19:51:52 +02:00
|
|
|
manageSpaceAtTheBottom(true);
|
2020-07-25 03:14:29 +02:00
|
|
|
|
2019-12-29 22:15:01 +01:00
|
|
|
bottomSheetBehavior.setPeekHeight(0);
|
|
|
|
cleanUp();
|
|
|
|
break;
|
|
|
|
case BottomSheetBehavior.STATE_EXPANDED:
|
2020-07-25 03:14:29 +02:00
|
|
|
moveFocusToMainFragment(false);
|
2020-08-15 19:51:52 +02:00
|
|
|
manageSpaceAtTheBottom(false);
|
2020-07-25 03:14:29 +02:00
|
|
|
|
2019-12-29 22:15:01 +01:00
|
|
|
bottomSheetBehavior.setPeekHeight(peekHeight);
|
2020-07-14 19:21:32 +02:00
|
|
|
// Disable click because overlay buttons located on top of buttons
|
|
|
|
// from the player
|
2019-12-29 22:15:01 +01:00
|
|
|
setOverlayElementsClickable(false);
|
2020-02-29 00:57:54 +01:00
|
|
|
hideSystemUiIfNeeded();
|
2020-06-27 05:25:50 +02:00
|
|
|
// Conditions when the player should be expanded to fullscreen
|
|
|
|
if (isLandscape()
|
2020-02-05 06:59:30 +01:00
|
|
|
&& player != null
|
|
|
|
&& player.isPlaying()
|
2020-06-27 05:25:50 +02:00
|
|
|
&& !player.isFullscreen()
|
2020-07-21 00:43:49 +02:00
|
|
|
&& !DeviceUtils.isTablet(activity)
|
2020-07-14 19:21:32 +02:00
|
|
|
&& player.videoPlayerSelected()) {
|
|
|
|
player.toggleFullscreen();
|
|
|
|
}
|
2020-09-17 18:01:20 +02:00
|
|
|
setOverlayLook(appBarLayout, behavior, 1);
|
2019-12-29 22:15:01 +01:00
|
|
|
break;
|
|
|
|
case BottomSheetBehavior.STATE_COLLAPSED:
|
2020-07-25 03:14:29 +02:00
|
|
|
moveFocusToMainFragment(true);
|
2020-09-29 05:22:53 +02:00
|
|
|
manageSpaceAtTheBottom(false);
|
|
|
|
|
|
|
|
bottomSheetBehavior.setPeekHeight(peekHeight);
|
2020-07-25 03:14:29 +02:00
|
|
|
|
2019-12-29 22:15:01 +01:00
|
|
|
// Re-enable clicks
|
|
|
|
setOverlayElementsClickable(true);
|
2020-07-14 19:21:32 +02:00
|
|
|
if (player != null) {
|
2021-01-08 18:35:33 +01:00
|
|
|
player.closeQueue();
|
2020-07-14 19:21:32 +02:00
|
|
|
}
|
2020-09-17 18:01:20 +02:00
|
|
|
setOverlayLook(appBarLayout, behavior, 0);
|
2019-12-29 22:15:01 +01:00
|
|
|
break;
|
|
|
|
case BottomSheetBehavior.STATE_DRAGGING:
|
|
|
|
case BottomSheetBehavior.STATE_SETTLING:
|
2020-07-14 19:21:32 +02:00
|
|
|
if (player != null && player.isFullscreen()) {
|
|
|
|
showSystemUi();
|
|
|
|
}
|
|
|
|
if (player != null && player.isControlsVisible()) {
|
|
|
|
player.hideControls(0, 0);
|
|
|
|
}
|
2019-12-29 22:15:01 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2020-07-12 02:59:47 +02:00
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onSlide(@NonNull final View bottomSheet, final float slideOffset) {
|
2019-12-29 22:15:01 +01:00
|
|
|
setOverlayLook(appBarLayout, behavior, slideOffset);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
// User opened a new page and the player will hide itself
|
|
|
|
activity.getSupportFragmentManager().addOnBackStackChangedListener(() -> {
|
2020-07-14 19:21:32 +02:00
|
|
|
if (bottomSheetBehavior.getState() == BottomSheetBehavior.STATE_EXPANDED) {
|
2019-12-29 22:15:01 +01:00
|
|
|
bottomSheetBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED);
|
2020-07-14 19:21:32 +02:00
|
|
|
}
|
2019-12-29 22:15:01 +01:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2020-10-18 20:19:50 +02:00
|
|
|
private void updateOverlayData(@Nullable final String overlayTitle,
|
2020-07-14 19:21:32 +02:00
|
|
|
@Nullable final String uploader,
|
|
|
|
@Nullable final String thumbnailUrl) {
|
2020-12-15 17:41:21 +01:00
|
|
|
overlayTitleTextView.setText(isEmpty(title) ? "" : title);
|
|
|
|
overlayChannelTextView.setText(isEmpty(uploader) ? "" : uploader);
|
2020-02-05 06:59:30 +01:00
|
|
|
overlayThumbnailImageView.setImageResource(R.drawable.dummy_thumbnail_dark);
|
2020-12-15 17:41:21 +01:00
|
|
|
if (!isEmpty(thumbnailUrl)) {
|
2020-07-13 03:17:21 +02:00
|
|
|
IMAGE_LOADER.displayImage(thumbnailUrl, overlayThumbnailImageView,
|
2020-07-12 02:59:47 +02:00
|
|
|
ImageDisplayConstants.DISPLAY_THUMBNAIL_OPTIONS, null);
|
2020-07-14 19:21:32 +02:00
|
|
|
}
|
2020-02-05 06:59:30 +01:00
|
|
|
}
|
|
|
|
|
2020-09-29 05:22:53 +02:00
|
|
|
private void setOverlayPlayPauseImage(final boolean playerIsPlaying) {
|
|
|
|
final int attr = playerIsPlaying
|
2020-07-14 19:21:32 +02:00
|
|
|
? R.attr.ic_pause
|
|
|
|
: R.attr.ic_play_arrow;
|
|
|
|
overlayPlayPauseButton.setImageResource(
|
|
|
|
ThemeHelper.resolveResourceIdFromAttr(activity, attr));
|
2019-12-29 22:15:01 +01:00
|
|
|
}
|
|
|
|
|
2020-07-14 19:21:32 +02:00
|
|
|
private void setOverlayLook(final AppBarLayout appBar,
|
|
|
|
final AppBarLayout.Behavior behavior,
|
|
|
|
final float slideOffset) {
|
2020-07-14 20:52:55 +02:00
|
|
|
// SlideOffset < 0 when mini player is about to close via swipe.
|
|
|
|
// Stop animation in this case
|
|
|
|
if (behavior == null || slideOffset < 0) {
|
|
|
|
return;
|
2019-12-29 22:15:01 +01:00
|
|
|
}
|
2020-07-14 20:52:55 +02:00
|
|
|
overlay.setAlpha(Math.min(MAX_OVERLAY_ALPHA, 1 - slideOffset));
|
|
|
|
// These numbers are not special. They just do a cool transition
|
|
|
|
behavior.setTopAndBottomOffset(
|
|
|
|
(int) (-thumbnailImageView.getHeight() * 2 * (1 - slideOffset) / 3));
|
|
|
|
appBar.requestLayout();
|
2019-12-29 22:15:01 +01:00
|
|
|
}
|
|
|
|
|
2020-07-12 02:59:47 +02:00
|
|
|
private void setOverlayElementsClickable(final boolean enable) {
|
2019-12-29 22:15:01 +01:00
|
|
|
overlayThumbnailImageView.setClickable(enable);
|
|
|
|
overlayThumbnailImageView.setLongClickable(enable);
|
|
|
|
overlayMetadata.setClickable(enable);
|
|
|
|
overlayMetadata.setLongClickable(enable);
|
|
|
|
overlayButtons.setClickable(enable);
|
|
|
|
overlayPlayPauseButton.setClickable(enable);
|
|
|
|
overlayCloseButton.setClickable(enable);
|
|
|
|
}
|
2018-11-20 23:10:50 +01:00
|
|
|
}
|