2017-04-09 17:34:00 +00:00
|
|
|
package org.schabi.newpipe.fragments.detail;
|
2015-09-04 00:15:03 +00:00
|
|
|
|
2019-12-29 21:15:01 +00:00
|
|
|
import android.animation.ValueAnimator;
|
2017-04-09 17:34:00 +00:00
|
|
|
import android.app.Activity;
|
2019-12-29 21:15:01 +00:00
|
|
|
import android.content.*;
|
|
|
|
import android.content.pm.ActivityInfo;
|
|
|
|
import android.graphics.Bitmap;
|
|
|
|
import android.media.AudioManager;
|
2017-03-31 18:15:26 +00:00
|
|
|
import android.os.Build;
|
2015-09-04 00:15:03 +00:00
|
|
|
import android.os.Bundle;
|
2019-12-29 21:15:01 +00:00
|
|
|
import android.os.Handler;
|
|
|
|
import android.os.IBinder;
|
2017-03-31 18:15:26 +00:00
|
|
|
import android.preference.PreferenceManager;
|
2019-12-29 21:15:01 +00:00
|
|
|
import android.provider.Settings;
|
|
|
|
import android.view.*;
|
|
|
|
import android.view.animation.DecelerateInterpolator;
|
|
|
|
import android.widget.*;
|
2019-10-04 12:59:08 +00:00
|
|
|
import androidx.annotation.DrawableRes;
|
|
|
|
import androidx.annotation.NonNull;
|
|
|
|
import androidx.annotation.Nullable;
|
2019-12-29 21:15:01 +00:00
|
|
|
import androidx.coordinatorlayout.widget.CoordinatorLayout;
|
|
|
|
import com.google.android.exoplayer2.ExoPlaybackException;
|
|
|
|
import com.google.android.exoplayer2.PlaybackParameters;
|
2019-10-04 12:59:08 +00:00
|
|
|
import com.google.android.material.appbar.AppBarLayout;
|
2019-12-29 21:15:01 +00:00
|
|
|
import com.google.android.material.bottomsheet.BottomSheetBehavior;
|
2019-10-04 12:59:08 +00:00
|
|
|
import com.google.android.material.tabs.TabLayout;
|
|
|
|
import androidx.fragment.app.Fragment;
|
|
|
|
import androidx.core.content.ContextCompat;
|
|
|
|
import androidx.viewpager.widget.ViewPager;
|
|
|
|
import androidx.appcompat.app.AppCompatActivity;
|
2017-03-31 18:15:26 +00:00
|
|
|
import android.text.Html;
|
2017-06-15 14:26:48 +00:00
|
|
|
import android.text.Spanned;
|
2017-04-26 19:32:04 +00:00
|
|
|
import android.text.TextUtils;
|
2017-03-31 18:15:26 +00:00
|
|
|
import android.text.method.LinkMovementMethod;
|
2017-07-19 08:26:26 +00:00
|
|
|
import android.text.util.Linkify;
|
2017-09-03 06:04:18 +00:00
|
|
|
import android.util.DisplayMetrics;
|
2015-11-29 12:06:27 +00:00
|
|
|
import android.util.Log;
|
2015-09-04 00:15:03 +00:00
|
|
|
|
2017-03-31 18:15:26 +00:00
|
|
|
import com.nostra13.universalimageloader.core.assist.FailReason;
|
2018-03-23 01:11:59 +00:00
|
|
|
import com.nostra13.universalimageloader.core.listener.ImageLoadingListener;
|
2017-03-31 18:15:26 +00:00
|
|
|
import com.nostra13.universalimageloader.core.listener.SimpleImageLoadingListener;
|
|
|
|
|
2016-08-02 19:17:54 +00:00
|
|
|
import org.schabi.newpipe.R;
|
2017-03-31 18:15:26 +00:00
|
|
|
import org.schabi.newpipe.ReCaptchaActivity;
|
|
|
|
import org.schabi.newpipe.download.DownloadDialog;
|
2017-06-17 11:43:09 +00:00
|
|
|
import org.schabi.newpipe.extractor.InfoItem;
|
2017-03-31 18:15:26 +00:00
|
|
|
import org.schabi.newpipe.extractor.NewPipe;
|
2018-12-23 21:07:27 +00:00
|
|
|
import org.schabi.newpipe.extractor.ServiceList;
|
2017-09-03 06:04:18 +00:00
|
|
|
import org.schabi.newpipe.extractor.exceptions.ContentNotAvailableException;
|
2018-09-23 01:32:19 +00:00
|
|
|
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
|
2017-09-03 06:04:18 +00:00
|
|
|
import org.schabi.newpipe.extractor.exceptions.ParsingException;
|
2018-07-08 15:46:21 +00:00
|
|
|
import org.schabi.newpipe.extractor.services.youtube.extractors.YoutubeStreamExtractor;
|
2017-09-03 06:04:18 +00:00
|
|
|
import org.schabi.newpipe.extractor.stream.AudioStream;
|
2018-06-19 01:27:30 +00:00
|
|
|
import org.schabi.newpipe.extractor.stream.Stream;
|
2017-09-03 06:04:18 +00:00
|
|
|
import org.schabi.newpipe.extractor.stream.StreamInfo;
|
2018-02-25 23:10:11 +00:00
|
|
|
import org.schabi.newpipe.extractor.stream.StreamType;
|
2017-09-03 06:04:18 +00:00
|
|
|
import org.schabi.newpipe.extractor.stream.VideoStream;
|
|
|
|
import org.schabi.newpipe.fragments.BackPressable;
|
|
|
|
import org.schabi.newpipe.fragments.BaseStateFragment;
|
2019-03-03 12:50:15 +00:00
|
|
|
import org.schabi.newpipe.fragments.EmptyFragment;
|
2018-10-02 15:09:16 +00:00
|
|
|
import org.schabi.newpipe.fragments.list.comments.CommentsFragment;
|
|
|
|
import org.schabi.newpipe.fragments.list.videos.RelatedVideosFragment;
|
2018-09-02 23:22:59 +00:00
|
|
|
import org.schabi.newpipe.local.dialog.PlaylistAppendDialog;
|
|
|
|
import org.schabi.newpipe.local.history.HistoryRecordManager;
|
2019-12-29 21:15:01 +00:00
|
|
|
import org.schabi.newpipe.player.*;
|
|
|
|
import org.schabi.newpipe.player.event.PlayerEventListener;
|
|
|
|
import org.schabi.newpipe.player.event.PlayerServiceEventListener;
|
|
|
|
import org.schabi.newpipe.player.helper.PlayerHelper;
|
|
|
|
import org.schabi.newpipe.player.playqueue.*;
|
2018-09-02 23:22:59 +00:00
|
|
|
import org.schabi.newpipe.report.ErrorActivity;
|
2017-06-28 05:27:32 +00:00
|
|
|
import org.schabi.newpipe.report.UserAction;
|
2019-12-29 21:15:01 +00:00
|
|
|
import org.schabi.newpipe.settings.SettingsContentObserver;
|
|
|
|
import org.schabi.newpipe.util.*;
|
2019-04-13 07:31:32 +00:00
|
|
|
import org.schabi.newpipe.views.AnimatedProgressBar;
|
2015-11-16 23:32:00 +00:00
|
|
|
|
2017-04-09 17:34:00 +00:00
|
|
|
import java.io.Serializable;
|
2017-09-03 06:04:18 +00:00
|
|
|
import java.util.Collection;
|
|
|
|
import java.util.LinkedList;
|
2018-04-08 11:08:19 +00:00
|
|
|
import java.util.List;
|
2019-04-13 07:31:32 +00:00
|
|
|
import java.util.concurrent.TimeUnit;
|
2017-09-03 06:04:18 +00:00
|
|
|
|
|
|
|
import icepick.State;
|
|
|
|
import io.reactivex.Single;
|
|
|
|
import io.reactivex.android.schedulers.AndroidSchedulers;
|
|
|
|
import io.reactivex.disposables.CompositeDisposable;
|
|
|
|
import io.reactivex.disposables.Disposable;
|
|
|
|
import io.reactivex.schedulers.Schedulers;
|
2017-04-09 17:34:00 +00:00
|
|
|
|
2019-02-15 19:53:26 +00:00
|
|
|
import static org.schabi.newpipe.extractor.StreamingService.ServiceInfo.MediaCapability.COMMENTS;
|
2019-12-29 21:15:01 +00:00
|
|
|
import static org.schabi.newpipe.player.playqueue.PlayQueueItem.RECOVERY_UNSET;
|
2017-05-08 13:33:26 +00:00
|
|
|
import static org.schabi.newpipe.util.AnimationUtils.animateView;
|
|
|
|
|
2018-02-16 10:31:25 +00:00
|
|
|
public class VideoDetailFragment
|
|
|
|
extends BaseStateFragment<StreamInfo>
|
|
|
|
implements BackPressable,
|
|
|
|
SharedPreferences.OnSharedPreferenceChangeListener,
|
|
|
|
View.OnClickListener,
|
2019-12-29 21:15:01 +00:00
|
|
|
View.OnLongClickListener,
|
|
|
|
PlayerEventListener,
|
|
|
|
PlayerServiceEventListener,
|
|
|
|
SettingsContentObserver.OnChangeListener {
|
2017-09-03 06:04:18 +00:00
|
|
|
public static final String AUTO_PLAY = "auto_play";
|
2017-03-31 18:15:26 +00:00
|
|
|
|
2019-12-29 21:15:01 +00:00
|
|
|
private boolean isFragmentStopped;
|
|
|
|
|
2017-09-03 06:04:18 +00:00
|
|
|
private int updateFlags = 0;
|
2017-04-12 06:07:15 +00:00
|
|
|
private static final int RELATED_STREAMS_UPDATE_FLAG = 0x1;
|
|
|
|
private static final int RESOLUTIONS_MENU_UPDATE_FLAG = 0x2;
|
2017-05-09 01:23:27 +00:00
|
|
|
private static final int TOOLBAR_ITEMS_UPDATE_FLAG = 0x4;
|
2019-04-13 07:31:32 +00:00
|
|
|
private static final int COMMENTS_UPDATE_FLAG = 0x8;
|
2019-12-29 21:15:01 +00:00
|
|
|
private static final float MAX_OVERLAY_ALPHA = 0.9f;
|
|
|
|
|
|
|
|
public static final String ACTION_SHOW_MAIN_PLAYER = "org.schabi.newpipe.fragments.VideoDetailFragment.ACTION_SHOW_MAIN_PLAYER";
|
2017-03-31 18:15:26 +00:00
|
|
|
|
|
|
|
private boolean autoPlayEnabled;
|
|
|
|
private boolean showRelatedStreams;
|
2018-09-02 23:22:59 +00:00
|
|
|
private boolean showComments;
|
2019-03-24 01:01:28 +00:00
|
|
|
private String selectedTabTag;
|
2017-03-31 18:15:26 +00:00
|
|
|
|
2018-09-02 23:22:59 +00:00
|
|
|
@State
|
|
|
|
protected int serviceId = Constants.NO_SERVICE_ID;
|
|
|
|
@State
|
|
|
|
protected String name;
|
|
|
|
@State
|
|
|
|
protected String url;
|
2019-12-29 21:15:01 +00:00
|
|
|
@State
|
|
|
|
protected PlayQueue playQueue;
|
|
|
|
@State
|
2020-01-06 10:39:01 +00:00
|
|
|
int bottomSheetState = BottomSheetBehavior.STATE_EXPANDED;
|
2017-09-03 06:04:18 +00:00
|
|
|
|
|
|
|
private StreamInfo currentInfo;
|
|
|
|
private Disposable currentWorker;
|
2018-09-02 23:22:59 +00:00
|
|
|
@NonNull
|
|
|
|
private CompositeDisposable disposables = new CompositeDisposable();
|
2019-04-13 07:31:32 +00:00
|
|
|
@Nullable
|
|
|
|
private Disposable positionSubscriber = null;
|
2017-06-28 01:39:33 +00:00
|
|
|
|
2018-04-08 11:08:19 +00:00
|
|
|
private List<VideoStream> sortedVideoStreams;
|
|
|
|
private int selectedVideoStreamIndex = -1;
|
2019-12-29 21:15:01 +00:00
|
|
|
private BottomSheetBehavior bottomSheetBehavior;
|
|
|
|
private BroadcastReceiver broadcastReceiver;
|
2018-02-16 11:18:15 +00:00
|
|
|
|
2017-03-31 18:15:26 +00:00
|
|
|
/*//////////////////////////////////////////////////////////////////////////
|
|
|
|
// Views
|
|
|
|
//////////////////////////////////////////////////////////////////////////*/
|
2018-03-10 16:16:51 +00:00
|
|
|
|
2018-02-16 11:18:15 +00:00
|
|
|
private Menu menu;
|
2017-03-31 18:15:26 +00:00
|
|
|
|
2017-04-26 19:32:04 +00:00
|
|
|
private Spinner spinnerToolbar;
|
2017-03-31 18:15:26 +00:00
|
|
|
|
2017-06-15 14:26:48 +00:00
|
|
|
private LinearLayout contentRootLayoutHiding;
|
2017-03-31 18:15:26 +00:00
|
|
|
|
2017-06-15 14:26:48 +00:00
|
|
|
private View thumbnailBackgroundButton;
|
2017-03-31 18:15:26 +00:00
|
|
|
private ImageView thumbnailImageView;
|
|
|
|
private ImageView thumbnailPlayButton;
|
2019-04-13 07:31:32 +00:00
|
|
|
private AnimatedProgressBar positionView;
|
2015-09-04 00:15:03 +00:00
|
|
|
|
2017-03-31 18:15:26 +00:00
|
|
|
private View videoTitleRoot;
|
|
|
|
private TextView videoTitleTextView;
|
|
|
|
private ImageView videoTitleToggleArrow;
|
|
|
|
private TextView videoCountView;
|
|
|
|
|
2017-04-26 19:32:04 +00:00
|
|
|
private TextView detailControlsBackground;
|
|
|
|
private TextView detailControlsPopup;
|
2018-01-17 22:32:09 +00:00
|
|
|
private TextView detailControlsAddToPlaylist;
|
2018-02-11 20:34:32 +00:00
|
|
|
private TextView detailControlsDownload;
|
2017-10-14 21:09:49 +00:00
|
|
|
private TextView appendControlsDetail;
|
2018-03-10 16:16:51 +00:00
|
|
|
private TextView detailDurationView;
|
2019-04-13 07:31:32 +00:00
|
|
|
private TextView detailPositionView;
|
2017-04-26 19:32:04 +00:00
|
|
|
|
2017-06-15 14:26:48 +00:00
|
|
|
private LinearLayout videoDescriptionRootLayout;
|
2017-03-31 18:15:26 +00:00
|
|
|
private TextView videoUploadDateView;
|
|
|
|
private TextView videoDescriptionView;
|
|
|
|
|
2017-04-28 03:58:50 +00:00
|
|
|
private View uploaderRootLayout;
|
2017-03-31 18:15:26 +00:00
|
|
|
private TextView uploaderTextView;
|
|
|
|
private ImageView uploaderThumb;
|
|
|
|
|
|
|
|
private TextView thumbsUpTextView;
|
|
|
|
private ImageView thumbsUpImageView;
|
|
|
|
private TextView thumbsDownTextView;
|
|
|
|
private ImageView thumbsDownImageView;
|
|
|
|
private TextView thumbsDisabledTextView;
|
|
|
|
|
2019-12-29 21:15:01 +00: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 15:09:16 +00:00
|
|
|
private static final String COMMENTS_TAB_TAG = "COMMENTS";
|
|
|
|
private static final String RELATED_TAB_TAG = "NEXT VIDEO";
|
2019-03-03 12:50:15 +00:00
|
|
|
private static final String EMPTY_TAB_TAG = "EMPTY TAB";
|
2018-09-02 23:22:59 +00:00
|
|
|
|
2018-10-02 15:09:16 +00:00
|
|
|
private AppBarLayout appBarLayout;
|
|
|
|
private ViewPager viewPager;
|
|
|
|
private TabAdaptor pageAdapter;
|
|
|
|
private TabLayout tabLayout;
|
2018-12-08 21:51:55 +00:00
|
|
|
private FrameLayout relatedStreamsLayout;
|
2018-09-02 23:22:59 +00:00
|
|
|
|
2019-12-29 21:15:01 +00:00
|
|
|
private SettingsContentObserver settingsContentObserver;
|
|
|
|
private ServiceConnection serviceConnection;
|
|
|
|
private boolean bounded;
|
|
|
|
private MainPlayer playerService;
|
|
|
|
private VideoPlayerImpl player;
|
|
|
|
|
|
|
|
|
|
|
|
/*//////////////////////////////////////////////////////////////////////////
|
|
|
|
// Service management
|
|
|
|
//////////////////////////////////////////////////////////////////////////*/
|
|
|
|
|
|
|
|
private ServiceConnection getServiceConnection(boolean playAfterConnect) {
|
|
|
|
return new ServiceConnection() {
|
|
|
|
@Override
|
|
|
|
public void onServiceDisconnected(ComponentName name) {
|
|
|
|
if (DEBUG) Log.d(TAG, "Player service is disconnected");
|
|
|
|
|
|
|
|
unbind();
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onServiceConnected(ComponentName compName, IBinder service) {
|
|
|
|
if (DEBUG) Log.d(TAG, "Player service is connected");
|
|
|
|
MainPlayer.LocalBinder localBinder = (MainPlayer.LocalBinder) service;
|
|
|
|
|
|
|
|
playerService = localBinder.getService();
|
|
|
|
player = localBinder.getPlayer();
|
|
|
|
|
|
|
|
startPlayerListener();
|
|
|
|
|
|
|
|
// It will do nothing if the player is not in fullscreen mode
|
|
|
|
hideSystemUIIfNeeded();
|
|
|
|
|
|
|
|
if (!player.videoPlayerSelected()) return;
|
|
|
|
|
|
|
|
if (currentInfo == null && !wasCleared()) selectAndLoadVideo(serviceId, url, name, playQueue);
|
|
|
|
|
|
|
|
if (player.getPlayQueue() != null) addVideoPlayerView();
|
|
|
|
|
|
|
|
// If the video is playing but orientation changed let's make the video in fullscreen again
|
|
|
|
|
|
|
|
if (isLandscape()) checkLandscape();
|
|
|
|
else if (player.isInFullscreen()) player.toggleFullscreen();
|
|
|
|
|
|
|
|
if (currentInfo != null && isAutoplayEnabled() && player.getParentActivity() == null || playAfterConnect)
|
|
|
|
openVideoPlayer();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
private void bind() {
|
|
|
|
if (DEBUG) Log.d(TAG, "bind() called");
|
|
|
|
|
|
|
|
Intent serviceIntent = new Intent(getContext(), MainPlayer.class);
|
|
|
|
final boolean success = getContext().bindService(serviceIntent, serviceConnection, Context.BIND_AUTO_CREATE);
|
|
|
|
|
|
|
|
if (!success) getContext().unbindService(serviceConnection);
|
|
|
|
bounded = success;
|
|
|
|
}
|
|
|
|
|
|
|
|
private void unbind() {
|
|
|
|
if (DEBUG) Log.d(TAG, "unbind() called");
|
|
|
|
|
|
|
|
if (bounded) {
|
|
|
|
getContext().unbindService(serviceConnection);
|
|
|
|
bounded = false;
|
|
|
|
stopPlayerListener();
|
|
|
|
playerService = null;
|
|
|
|
player = null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private void startPlayerListener() {
|
|
|
|
if (player != null) player.setFragmentListener(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
private void stopPlayerListener() {
|
|
|
|
if (player != null) player.removeFragmentListener(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
private void startService(boolean playAfterConnect) {
|
|
|
|
getContext().startService(new Intent(getContext(), MainPlayer.class));
|
|
|
|
serviceConnection = getServiceConnection(playAfterConnect);
|
|
|
|
bind();
|
|
|
|
}
|
|
|
|
|
|
|
|
private void stopService() {
|
|
|
|
getContext().stopService(new Intent(getContext(), MainPlayer.class));
|
|
|
|
unbind();
|
|
|
|
}
|
|
|
|
|
2018-02-16 11:18:15 +00:00
|
|
|
|
2017-04-09 17:34:00 +00:00
|
|
|
/*////////////////////////////////////////////////////////////////////////*/
|
|
|
|
|
2019-12-29 21:15:01 +00:00
|
|
|
public static VideoDetailFragment getInstance(int serviceId, String videoUrl, String name, PlayQueue playQueue) {
|
2017-09-03 06:04:18 +00:00
|
|
|
VideoDetailFragment instance = new VideoDetailFragment();
|
2019-12-29 21:15:01 +00:00
|
|
|
instance.setInitialData(serviceId, videoUrl, name, playQueue);
|
2017-04-09 17:34:00 +00:00
|
|
|
return instance;
|
|
|
|
}
|
|
|
|
|
2017-03-31 18:15:26 +00:00
|
|
|
/*//////////////////////////////////////////////////////////////////////////
|
2017-04-09 17:34:00 +00:00
|
|
|
// Fragment's Lifecycle
|
2017-03-31 18:15:26 +00:00
|
|
|
//////////////////////////////////////////////////////////////////////////*/
|
|
|
|
|
|
|
|
@Override
|
2018-09-02 23:22:59 +00:00
|
|
|
public void
|
|
|
|
onCreate(Bundle savedInstanceState) {
|
2015-09-04 00:15:03 +00:00
|
|
|
super.onCreate(savedInstanceState);
|
2017-09-03 06:04:18 +00:00
|
|
|
setHasOptionsMenu(true);
|
2017-03-31 18:15:26 +00:00
|
|
|
|
2019-12-29 21:15:01 +00:00
|
|
|
// Let's play all streams automatically
|
|
|
|
setAutoplay(true);
|
|
|
|
|
|
|
|
activity.setVolumeControlStream(AudioManager.STREAM_MUSIC);
|
|
|
|
|
2018-02-16 10:31:25 +00:00
|
|
|
showRelatedStreams = PreferenceManager.getDefaultSharedPreferences(activity)
|
|
|
|
.getBoolean(getString(R.string.show_next_video_key), true);
|
2018-09-02 23:22:59 +00:00
|
|
|
|
|
|
|
showComments = PreferenceManager.getDefaultSharedPreferences(activity)
|
2018-10-02 15:26:14 +00:00
|
|
|
.getBoolean(getString(R.string.show_comments_key), true);
|
2018-09-02 23:22:59 +00:00
|
|
|
|
2019-03-24 01:01:28 +00:00
|
|
|
selectedTabTag = PreferenceManager.getDefaultSharedPreferences(activity)
|
|
|
|
.getString(getString(R.string.stream_info_selected_tab_key), COMMENTS_TAB_TAG);
|
|
|
|
|
2018-02-16 10:31:25 +00:00
|
|
|
PreferenceManager.getDefaultSharedPreferences(activity)
|
|
|
|
.registerOnSharedPreferenceChangeListener(this);
|
2019-12-29 21:15:01 +00:00
|
|
|
|
|
|
|
startService(false);
|
|
|
|
setupBroadcastReceiver();
|
|
|
|
settingsContentObserver = new SettingsContentObserver(new Handler(), this);
|
2017-04-09 17:34:00 +00:00
|
|
|
}
|
2015-09-04 00:15:03 +00:00
|
|
|
|
2017-04-09 17:34:00 +00:00
|
|
|
@Override
|
2018-04-06 07:35:44 +00:00
|
|
|
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
2017-04-09 17:34:00 +00:00
|
|
|
return inflater.inflate(R.layout.fragment_video_detail, container, false);
|
|
|
|
}
|
2017-03-31 18:15:26 +00:00
|
|
|
|
2017-04-09 17:34:00 +00:00
|
|
|
@Override
|
2017-09-03 06:04:18 +00:00
|
|
|
public void onPause() {
|
|
|
|
super.onPause();
|
|
|
|
if (currentWorker != null) currentWorker.dispose();
|
2019-12-29 21:15:01 +00:00
|
|
|
|
|
|
|
setupBrightness(true);
|
|
|
|
getContext().getContentResolver().unregisterContentObserver(settingsContentObserver);
|
2019-03-24 01:01:28 +00:00
|
|
|
PreferenceManager.getDefaultSharedPreferences(getContext())
|
|
|
|
.edit()
|
|
|
|
.putString(getString(R.string.stream_info_selected_tab_key), pageAdapter.getItemTitle(viewPager.getCurrentItem()))
|
|
|
|
.apply();
|
2017-08-12 04:50:25 +00:00
|
|
|
}
|
|
|
|
|
2017-04-26 19:32:04 +00:00
|
|
|
@Override
|
|
|
|
public void onResume() {
|
|
|
|
super.onResume();
|
|
|
|
|
2019-12-29 21:15:01 +00:00
|
|
|
isFragmentStopped = false;
|
|
|
|
getContext().getContentResolver().registerContentObserver(
|
|
|
|
android.provider.Settings.System.CONTENT_URI, true,
|
|
|
|
settingsContentObserver);
|
|
|
|
|
|
|
|
setupBrightness(false);
|
|
|
|
|
2017-04-26 19:32:04 +00:00
|
|
|
if (updateFlags != 0) {
|
2017-09-03 06:04:18 +00:00
|
|
|
if (!isLoading.get() && currentInfo != null) {
|
2018-10-02 15:09:16 +00:00
|
|
|
if ((updateFlags & RELATED_STREAMS_UPDATE_FLAG) != 0) startLoading(false);
|
2018-02-16 11:18:15 +00:00
|
|
|
if ((updateFlags & RESOLUTIONS_MENU_UPDATE_FLAG) != 0) setupActionBar(currentInfo);
|
2018-10-02 15:09:16 +00:00
|
|
|
if ((updateFlags & COMMENTS_UPDATE_FLAG) != 0) startLoading(false);
|
2017-04-26 19:32:04 +00:00
|
|
|
}
|
2017-05-09 01:23:27 +00:00
|
|
|
|
2018-02-16 10:31:25 +00:00
|
|
|
if ((updateFlags & TOOLBAR_ITEMS_UPDATE_FLAG) != 0
|
2018-02-16 11:18:15 +00:00
|
|
|
&& menu != null) {
|
|
|
|
updateMenuItemVisibility();
|
2018-02-16 10:31:25 +00:00
|
|
|
}
|
2018-09-02 23:22:59 +00:00
|
|
|
|
2017-04-26 19:32:04 +00:00
|
|
|
updateFlags = 0;
|
|
|
|
}
|
|
|
|
|
2017-09-03 06:04:18 +00:00
|
|
|
// Check if it was loading when the fragment was stopped/paused,
|
2019-12-29 21:15:01 +00:00
|
|
|
if (wasLoading.getAndSet(false) && !wasCleared()) {
|
|
|
|
selectAndLoadVideo(serviceId, url, name, playQueue);
|
2019-04-13 07:31:32 +00:00
|
|
|
} else if (currentInfo != null) {
|
|
|
|
updateProgressInfo(currentInfo);
|
2017-09-03 06:04:18 +00:00
|
|
|
}
|
2019-12-29 21:15:01 +00:00
|
|
|
|
|
|
|
if (player != null && player.videoPlayerSelected()) addVideoPlayerView();
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onStop() {
|
|
|
|
super.onStop();
|
|
|
|
|
|
|
|
isFragmentStopped = true;
|
2017-04-26 19:32:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onDestroy() {
|
|
|
|
super.onDestroy();
|
2019-12-29 21:15:01 +00:00
|
|
|
|
2020-01-06 10:39:01 +00:00
|
|
|
if (!activity.isFinishing()) unbind();
|
|
|
|
else stopService();
|
2019-12-29 21:15:01 +00:00
|
|
|
|
2018-02-16 10:31:25 +00:00
|
|
|
PreferenceManager.getDefaultSharedPreferences(activity)
|
|
|
|
.unregisterOnSharedPreferenceChangeListener(this);
|
2019-12-29 21:15:01 +00:00
|
|
|
getActivity().unregisterReceiver(broadcastReceiver);
|
2017-09-03 06:04:18 +00:00
|
|
|
|
2019-04-13 07:31:32 +00:00
|
|
|
if (positionSubscriber != null) positionSubscriber.dispose();
|
2017-09-03 06:04:18 +00:00
|
|
|
if (currentWorker != null) currentWorker.dispose();
|
|
|
|
if (disposables != null) disposables.clear();
|
2019-04-13 07:31:32 +00:00
|
|
|
positionSubscriber = null;
|
2017-09-03 06:04:18 +00:00
|
|
|
currentWorker = null;
|
|
|
|
disposables = null;
|
2017-03-31 18:15:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2017-04-09 17:34:00 +00:00
|
|
|
public void onDestroyView() {
|
2017-04-26 19:32:04 +00:00
|
|
|
if (DEBUG) Log.d(TAG, "onDestroyView() called");
|
|
|
|
spinnerToolbar.setOnItemSelectedListener(null);
|
2017-09-03 06:04:18 +00:00
|
|
|
spinnerToolbar.setAdapter(null);
|
2017-04-26 19:32:04 +00:00
|
|
|
super.onDestroyView();
|
2017-04-09 17:34:00 +00:00
|
|
|
}
|
|
|
|
|
2017-03-31 18:15:26 +00:00
|
|
|
@Override
|
|
|
|
public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
|
|
|
super.onActivityResult(requestCode, resultCode, data);
|
|
|
|
switch (requestCode) {
|
|
|
|
case ReCaptchaActivity.RECAPTCHA_REQUEST:
|
2017-04-09 17:34:00 +00:00
|
|
|
if (resultCode == Activity.RESULT_OK) {
|
2017-09-03 06:04:18 +00:00
|
|
|
NavigationHelper.openVideoDetailFragment(getFragmentManager(), serviceId, url, name);
|
2017-03-31 18:15:26 +00:00
|
|
|
} else Log.e(TAG, "ReCaptcha failed");
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
Log.e(TAG, "Request code from activity not supported [" + requestCode + "]");
|
|
|
|
break;
|
|
|
|
}
|
2015-10-29 16:56:35 +00:00
|
|
|
}
|
|
|
|
|
2016-01-01 22:04:29 +00:00
|
|
|
@Override
|
2017-03-31 18:15:26 +00:00
|
|
|
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
|
|
|
|
if (key.equals(getString(R.string.show_next_video_key))) {
|
|
|
|
showRelatedStreams = sharedPreferences.getBoolean(key, true);
|
2017-04-12 06:07:15 +00:00
|
|
|
updateFlags |= RELATED_STREAMS_UPDATE_FLAG;
|
2017-09-03 06:04:18 +00:00
|
|
|
} else if (key.equals(getString(R.string.default_video_format_key))
|
2017-04-12 06:07:15 +00:00
|
|
|
|| key.equals(getString(R.string.default_resolution_key))
|
2017-05-15 03:57:57 +00:00
|
|
|
|| key.equals(getString(R.string.show_higher_resolutions_key))
|
|
|
|
|| key.equals(getString(R.string.use_external_video_player_key))) {
|
2017-04-12 06:07:15 +00:00
|
|
|
updateFlags |= RESOLUTIONS_MENU_UPDATE_FLAG;
|
2017-05-09 01:23:27 +00:00
|
|
|
} else if (key.equals(getString(R.string.show_play_with_kodi_key))) {
|
|
|
|
updateFlags |= TOOLBAR_ITEMS_UPDATE_FLAG;
|
2018-10-02 15:26:14 +00:00
|
|
|
} else if (key.equals(getString(R.string.show_comments_key))) {
|
2018-09-02 23:22:59 +00:00
|
|
|
showComments = sharedPreferences.getBoolean(key, true);
|
|
|
|
updateFlags |= COMMENTS_UPDATE_FLAG;
|
2017-03-31 18:15:26 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-09-03 06:04:18 +00:00
|
|
|
/*//////////////////////////////////////////////////////////////////////////
|
|
|
|
// State Saving
|
|
|
|
//////////////////////////////////////////////////////////////////////////*/
|
|
|
|
|
|
|
|
private static final String INFO_KEY = "info_key";
|
|
|
|
private static final String STACK_KEY = "stack_key";
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onSaveInstanceState(Bundle outState) {
|
|
|
|
super.onSaveInstanceState(outState);
|
|
|
|
|
|
|
|
// Check if the next video label and video is visible,
|
|
|
|
// if it is, include the two elements in the next check
|
2017-12-08 14:05:08 +00:00
|
|
|
int nextCount = currentInfo != null && currentInfo.getNextVideo() != null ? 2 : 0;
|
2017-09-03 06:04:18 +00:00
|
|
|
|
|
|
|
if (!isLoading.get() && currentInfo != null && isVisible()) {
|
2018-09-18 23:43:55 +00:00
|
|
|
outState.putSerializable(INFO_KEY, currentInfo);
|
2017-09-03 06:04:18 +00:00
|
|
|
}
|
|
|
|
|
2019-12-29 21:15:01 +00:00
|
|
|
if (playQueue != null) outState.putSerializable(VideoPlayer.PLAY_QUEUE_KEY, playQueue);
|
2017-09-03 06:04:18 +00:00
|
|
|
outState.putSerializable(STACK_KEY, stack);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
protected void onRestoreInstanceState(@NonNull Bundle savedState) {
|
|
|
|
super.onRestoreInstanceState(savedState);
|
|
|
|
|
|
|
|
Serializable serializable = savedState.getSerializable(INFO_KEY);
|
|
|
|
if (serializable instanceof StreamInfo) {
|
|
|
|
//noinspection unchecked
|
|
|
|
currentInfo = (StreamInfo) serializable;
|
2018-09-23 01:32:19 +00:00
|
|
|
InfoCache.getInstance().putInfo(serviceId, url, currentInfo, InfoItem.InfoType.STREAM);
|
2017-09-03 06:04:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
serializable = savedState.getSerializable(STACK_KEY);
|
|
|
|
if (serializable instanceof Collection) {
|
|
|
|
//noinspection unchecked
|
|
|
|
stack.addAll((Collection<? extends StackItem>) serializable);
|
|
|
|
}
|
2019-12-29 21:15:01 +00:00
|
|
|
playQueue = (PlayQueue) savedState.getSerializable(VideoPlayer.PLAY_QUEUE_KEY);
|
2017-09-03 06:04:18 +00:00
|
|
|
}
|
|
|
|
|
2017-04-26 19:32:04 +00:00
|
|
|
/*//////////////////////////////////////////////////////////////////////////
|
|
|
|
// OnClick
|
|
|
|
//////////////////////////////////////////////////////////////////////////*/
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onClick(View v) {
|
2017-09-03 06:04:18 +00:00
|
|
|
if (isLoading.get() || currentInfo == null) return;
|
2017-04-26 19:32:04 +00:00
|
|
|
|
|
|
|
switch (v.getId()) {
|
|
|
|
case R.id.detail_controls_background:
|
2017-10-13 00:02:07 +00:00
|
|
|
openBackgroundPlayer(false);
|
2017-04-26 19:32:04 +00:00
|
|
|
break;
|
|
|
|
case R.id.detail_controls_popup:
|
2017-10-13 00:02:07 +00:00
|
|
|
openPopupPlayer(false);
|
2017-04-26 19:32:04 +00:00
|
|
|
break;
|
2018-01-17 22:32:09 +00:00
|
|
|
case R.id.detail_controls_playlist_append:
|
|
|
|
if (getFragmentManager() != null && currentInfo != null) {
|
2018-01-22 03:32:49 +00:00
|
|
|
PlaylistAppendDialog.fromStreamInfo(currentInfo)
|
|
|
|
.show(getFragmentManager(), TAG);
|
2018-01-17 22:32:09 +00:00
|
|
|
}
|
|
|
|
break;
|
2018-02-11 20:34:32 +00:00
|
|
|
case R.id.detail_controls_download:
|
2019-08-15 02:00:11 +00:00
|
|
|
if (PermissionHelper.checkStoragePermissions(activity,
|
|
|
|
PermissionHelper.DOWNLOAD_DIALOG_REQUEST_CODE)) {
|
|
|
|
this.openDownloadDialog();
|
|
|
|
}
|
2018-02-11 20:34:32 +00:00
|
|
|
break;
|
2017-06-15 14:26:48 +00:00
|
|
|
case R.id.detail_uploader_root_layout:
|
2019-12-29 21:15:01 +00:00
|
|
|
openChannel();
|
2017-04-26 19:32:04 +00:00
|
|
|
break;
|
2017-06-15 14:26:48 +00:00
|
|
|
case R.id.detail_thumbnail_root_layout:
|
2020-01-03 16:19:14 +00:00
|
|
|
openVideoPlayer();
|
2017-04-26 19:32:04 +00:00
|
|
|
break;
|
|
|
|
case R.id.detail_title_root_layout:
|
|
|
|
toggleTitleAndDescription();
|
|
|
|
break;
|
2019-12-29 21:15:01 +00: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:
|
|
|
|
if (player != null) {
|
|
|
|
player.onPlayPause();
|
|
|
|
player.hideControls(0,0);
|
2020-01-03 16:19:14 +00:00
|
|
|
showSystemUi();
|
2019-12-29 21:15:01 +00:00
|
|
|
}
|
|
|
|
else openVideoPlayer();
|
|
|
|
|
|
|
|
setOverlayPlayPauseImage();
|
|
|
|
break;
|
|
|
|
case R.id.overlay_close_button:
|
|
|
|
cleanUp();
|
|
|
|
bottomSheetBehavior.setState(BottomSheetBehavior.STATE_HIDDEN);
|
|
|
|
break;
|
2017-04-26 19:32:04 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-10-13 00:02:07 +00:00
|
|
|
@Override
|
|
|
|
public boolean onLongClick(View v) {
|
|
|
|
if (isLoading.get() || currentInfo == null) return false;
|
|
|
|
|
|
|
|
switch (v.getId()) {
|
|
|
|
case R.id.detail_controls_background:
|
|
|
|
openBackgroundPlayer(true);
|
|
|
|
break;
|
|
|
|
case R.id.detail_controls_popup:
|
|
|
|
openPopupPlayer(true);
|
|
|
|
break;
|
2018-04-08 19:53:15 +00:00
|
|
|
case R.id.detail_controls_download:
|
|
|
|
NavigationHelper.openDownloads(getActivity());
|
|
|
|
break;
|
2019-12-29 21:15:01 +00:00
|
|
|
case R.id.overlay_thumbnail:
|
|
|
|
case R.id.overlay_metadata_layout:
|
|
|
|
openChannel();
|
|
|
|
break;
|
2017-10-13 00:02:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2017-04-26 19:32:04 +00:00
|
|
|
private void toggleTitleAndDescription() {
|
2018-12-08 21:51:55 +00:00
|
|
|
if (videoDescriptionRootLayout.getVisibility() == View.VISIBLE) {
|
|
|
|
videoTitleTextView.setMaxLines(1);
|
|
|
|
videoDescriptionRootLayout.setVisibility(View.GONE);
|
|
|
|
videoTitleToggleArrow.setImageResource(R.drawable.arrow_down);
|
|
|
|
} else {
|
|
|
|
videoTitleTextView.setMaxLines(10);
|
|
|
|
videoDescriptionRootLayout.setVisibility(View.VISIBLE);
|
|
|
|
videoTitleToggleArrow.setImageResource(R.drawable.arrow_up);
|
2017-04-26 19:32:04 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-03-31 18:15:26 +00:00
|
|
|
/*//////////////////////////////////////////////////////////////////////////
|
|
|
|
// Init
|
|
|
|
//////////////////////////////////////////////////////////////////////////*/
|
|
|
|
|
2017-09-03 06:04:18 +00:00
|
|
|
@Override
|
2017-04-26 19:32:04 +00:00
|
|
|
protected void initViews(View rootView, Bundle savedInstanceState) {
|
|
|
|
super.initViews(rootView, savedInstanceState);
|
2018-03-10 16:16:51 +00:00
|
|
|
spinnerToolbar = activity.findViewById(R.id.toolbar).findViewById(R.id.toolbar_spinner);
|
2017-03-31 18:15:26 +00:00
|
|
|
|
2017-06-15 14:26:48 +00:00
|
|
|
thumbnailBackgroundButton = rootView.findViewById(R.id.detail_thumbnail_root_layout);
|
2017-09-03 06:04:18 +00:00
|
|
|
thumbnailImageView = rootView.findViewById(R.id.detail_thumbnail_image_view);
|
|
|
|
thumbnailPlayButton = rootView.findViewById(R.id.detail_thumbnail_play_button);
|
2017-03-31 18:15:26 +00:00
|
|
|
|
2017-09-03 06:04:18 +00:00
|
|
|
contentRootLayoutHiding = rootView.findViewById(R.id.detail_content_root_hiding);
|
2017-03-31 18:15:26 +00:00
|
|
|
|
2017-04-09 17:34:00 +00:00
|
|
|
videoTitleRoot = rootView.findViewById(R.id.detail_title_root_layout);
|
2017-09-03 06:04:18 +00: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 07:31:32 +00:00
|
|
|
positionView = rootView.findViewById(R.id.position_view);
|
2017-03-31 18:15:26 +00:00
|
|
|
|
2017-09-03 06:04:18 +00:00
|
|
|
detailControlsBackground = rootView.findViewById(R.id.detail_controls_background);
|
|
|
|
detailControlsPopup = rootView.findViewById(R.id.detail_controls_popup);
|
2018-01-17 22:32:09 +00:00
|
|
|
detailControlsAddToPlaylist = rootView.findViewById(R.id.detail_controls_playlist_append);
|
2018-02-11 20:34:32 +00:00
|
|
|
detailControlsDownload = rootView.findViewById(R.id.detail_controls_download);
|
2017-10-14 21:09:49 +00:00
|
|
|
appendControlsDetail = rootView.findViewById(R.id.touch_append_detail);
|
2018-03-10 16:16:51 +00:00
|
|
|
detailDurationView = rootView.findViewById(R.id.detail_duration_view);
|
2019-04-13 07:31:32 +00:00
|
|
|
detailPositionView = rootView.findViewById(R.id.detail_position_view);
|
2017-04-26 19:32:04 +00:00
|
|
|
|
2017-09-03 06:04:18 +00: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);
|
|
|
|
videoDescriptionView.setMovementMethod(LinkMovementMethod.getInstance());
|
|
|
|
videoDescriptionView.setAutoLinkMask(Linkify.WEB_URLS);
|
2017-03-31 18:15:26 +00:00
|
|
|
|
2017-09-03 06:04:18 +00: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 18:15:26 +00:00
|
|
|
|
2017-04-28 03:58:50 +00:00
|
|
|
uploaderRootLayout = rootView.findViewById(R.id.detail_uploader_root_layout);
|
2017-09-03 06:04:18 +00:00
|
|
|
uploaderTextView = rootView.findViewById(R.id.detail_uploader_text_view);
|
|
|
|
uploaderThumb = rootView.findViewById(R.id.detail_uploader_thumbnail_view);
|
2017-03-31 18:15:26 +00:00
|
|
|
|
2019-12-29 21:15:01 +00: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 15:09:16 +00:00
|
|
|
appBarLayout = rootView.findViewById(R.id.appbarlayout);
|
|
|
|
viewPager = rootView.findViewById(R.id.viewpager);
|
|
|
|
pageAdapter = new TabAdaptor(getChildFragmentManager());
|
|
|
|
viewPager.setAdapter(pageAdapter);
|
|
|
|
tabLayout = rootView.findViewById(R.id.tablayout);
|
|
|
|
tabLayout.setupWithViewPager(viewPager);
|
2018-09-23 01:32:19 +00:00
|
|
|
|
2018-12-08 21:51:55 +00:00
|
|
|
relatedStreamsLayout = rootView.findViewById(R.id.relatedStreamsLayout);
|
|
|
|
|
2018-09-23 01:32:19 +00:00
|
|
|
setHeightThumbnail();
|
|
|
|
}
|
|
|
|
|
2017-09-03 06:04:18 +00:00
|
|
|
@Override
|
2017-04-26 19:32:04 +00:00
|
|
|
protected void initListeners() {
|
|
|
|
super.initListeners();
|
2017-03-31 18:15:26 +00:00
|
|
|
|
2017-04-26 19:32:04 +00:00
|
|
|
videoTitleRoot.setOnClickListener(this);
|
2017-06-15 14:26:48 +00:00
|
|
|
uploaderRootLayout.setOnClickListener(this);
|
2017-04-26 19:32:04 +00:00
|
|
|
thumbnailBackgroundButton.setOnClickListener(this);
|
|
|
|
detailControlsBackground.setOnClickListener(this);
|
|
|
|
detailControlsPopup.setOnClickListener(this);
|
2018-01-17 22:32:09 +00:00
|
|
|
detailControlsAddToPlaylist.setOnClickListener(this);
|
2018-02-11 20:34:32 +00:00
|
|
|
detailControlsDownload.setOnClickListener(this);
|
2018-04-08 19:53:15 +00:00
|
|
|
detailControlsDownload.setOnLongClickListener(this);
|
2017-10-13 00:02:07 +00:00
|
|
|
|
|
|
|
detailControlsBackground.setLongClickable(true);
|
|
|
|
detailControlsPopup.setLongClickable(true);
|
|
|
|
detailControlsBackground.setOnLongClickListener(this);
|
|
|
|
detailControlsPopup.setOnLongClickListener(this);
|
2019-12-29 21:15:01 +00: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 21:09:49 +00:00
|
|
|
detailControlsBackground.setOnTouchListener(getOnControlsTouchListener());
|
|
|
|
detailControlsPopup.setOnTouchListener(getOnControlsTouchListener());
|
2019-12-29 21:15:01 +00:00
|
|
|
|
|
|
|
setupBottomPlayer();
|
2017-10-14 21:09:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
private View.OnTouchListener getOnControlsTouchListener() {
|
2018-02-11 20:34:32 +00:00
|
|
|
return (View view, MotionEvent motionEvent) -> {
|
2018-02-16 10:31:25 +00:00
|
|
|
if (!PreferenceManager.getDefaultSharedPreferences(activity)
|
|
|
|
.getBoolean(getString(R.string.show_hold_to_append_key), true)) {
|
|
|
|
return false;
|
|
|
|
}
|
2018-02-11 20:34:32 +00:00
|
|
|
|
|
|
|
if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) {
|
2018-02-11 23:43:12 +00:00
|
|
|
animateView(appendControlsDetail, true, 250, 0, () ->
|
|
|
|
animateView(appendControlsDetail, false, 1500, 1000));
|
2017-10-14 21:09:49 +00:00
|
|
|
}
|
2018-02-11 20:34:32 +00:00
|
|
|
return false;
|
2017-10-14 21:09:49 +00:00
|
|
|
};
|
2017-03-31 18:15:26 +00:00
|
|
|
}
|
|
|
|
|
2018-03-23 01:11:59 +00:00
|
|
|
private void initThumbnailViews(@NonNull StreamInfo info) {
|
2017-09-03 06:04:18 +00:00
|
|
|
thumbnailImageView.setImageResource(R.drawable.dummy_thumbnail_dark);
|
2019-12-29 21:15:01 +00:00
|
|
|
overlayThumbnailImageView.setImageResource(R.drawable.dummy_thumbnail_dark);
|
|
|
|
|
2017-12-08 14:05:08 +00:00
|
|
|
if (!TextUtils.isEmpty(info.getThumbnailUrl())) {
|
2018-03-23 01:11:59 +00:00
|
|
|
final String infoServiceName = NewPipe.getNameOfService(info.getServiceId());
|
2019-12-29 21:15:01 +00:00
|
|
|
final ImageLoadingListener loadingListener = new SimpleImageLoadingListener() {
|
2017-04-26 19:32:04 +00:00
|
|
|
@Override
|
|
|
|
public void onLoadingFailed(String imageUri, View view, FailReason failReason) {
|
2018-03-23 01:11:59 +00:00
|
|
|
showSnackBarError(failReason.getCause(), UserAction.LOAD_IMAGE,
|
|
|
|
infoServiceName, imageUri, R.string.could_not_load_thumbnails);
|
2017-04-26 19:32:04 +00:00
|
|
|
}
|
2019-12-29 21:15:01 +00:00
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) {
|
|
|
|
overlayThumbnailImageView.setImageBitmap(loadedImage);
|
|
|
|
}
|
2018-03-23 01:11:59 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
imageLoader.displayImage(info.getThumbnailUrl(), thumbnailImageView,
|
2019-12-29 21:15:01 +00:00
|
|
|
ImageDisplayConstants.DISPLAY_THUMBNAIL_OPTIONS, loadingListener);
|
2017-09-03 06:04:18 +00:00
|
|
|
}
|
2018-02-16 10:31:25 +00:00
|
|
|
|
2017-12-22 15:53:43 +00:00
|
|
|
if (!TextUtils.isEmpty(info.getUploaderAvatarUrl())) {
|
2018-03-16 03:07:20 +00:00
|
|
|
imageLoader.displayImage(info.getUploaderAvatarUrl(), uploaderThumb,
|
|
|
|
ImageDisplayConstants.DISPLAY_AVATAR_OPTIONS);
|
2017-03-31 18:15:26 +00:00
|
|
|
}
|
2016-01-01 22:04:29 +00:00
|
|
|
}
|
|
|
|
|
2017-03-31 18:15:26 +00:00
|
|
|
|
|
|
|
/*//////////////////////////////////////////////////////////////////////////
|
|
|
|
// Menu
|
|
|
|
//////////////////////////////////////////////////////////////////////////*/
|
|
|
|
|
2015-10-29 16:56:35 +00:00
|
|
|
@Override
|
2017-04-09 17:34:00 +00:00
|
|
|
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
|
2018-02-16 11:18:15 +00:00
|
|
|
this.menu = menu;
|
|
|
|
|
|
|
|
// CAUTION set item properties programmatically otherwise it would not be accepted by
|
|
|
|
// appcompat itemsinflater.inflate(R.menu.videoitem_detail, menu);
|
|
|
|
|
2019-12-29 21:15:01 +00:00
|
|
|
/*inflater.inflate(R.menu.video_detail_menu, menu);
|
2018-02-16 11:18:15 +00:00
|
|
|
|
|
|
|
updateMenuItemVisibility();
|
|
|
|
|
2017-04-09 17:34:00 +00:00
|
|
|
ActionBar supportActionBar = activity.getSupportActionBar();
|
|
|
|
if (supportActionBar != null) {
|
|
|
|
supportActionBar.setDisplayHomeAsUpEnabled(true);
|
|
|
|
supportActionBar.setDisplayShowTitleEnabled(false);
|
2019-12-29 21:15:01 +00:00
|
|
|
}*/
|
2015-09-04 00:15:03 +00:00
|
|
|
}
|
|
|
|
|
2018-02-16 11:18:15 +00:00
|
|
|
private void updateMenuItemVisibility() {
|
2019-12-29 21:15:01 +00:00
|
|
|
/*// show kodi if set in settings
|
2018-02-16 11:18:15 +00:00
|
|
|
menu.findItem(R.id.action_play_with_kodi).setVisible(
|
|
|
|
PreferenceManager.getDefaultSharedPreferences(activity).getBoolean(
|
2019-12-29 21:15:01 +00:00
|
|
|
activity.getString(R.string.show_play_with_kodi_key), false));*/
|
2018-02-16 11:18:15 +00:00
|
|
|
}
|
|
|
|
|
2015-09-04 00:15:03 +00:00
|
|
|
@Override
|
|
|
|
public boolean onOptionsItemSelected(MenuItem item) {
|
2018-09-02 23:22:59 +00:00
|
|
|
if (isLoading.get()) {
|
2018-02-16 11:18:15 +00:00
|
|
|
// if is still loading block menu
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
int id = item.getItemId();
|
|
|
|
switch (id) {
|
|
|
|
case R.id.menu_item_share: {
|
2018-04-06 07:35:44 +00:00
|
|
|
if (currentInfo != null) {
|
2019-04-06 18:17:04 +00:00
|
|
|
ShareUtils.shareUrl(this.getContext(), currentInfo.getName(), currentInfo.getOriginalUrl());
|
2018-02-16 11:18:15 +00:00
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
case R.id.menu_item_openInBrowser: {
|
2018-04-06 07:35:44 +00:00
|
|
|
if (currentInfo != null) {
|
2019-04-06 18:17:04 +00:00
|
|
|
ShareUtils.openUrlInBrowser(this.getContext(), currentInfo.getOriginalUrl());
|
2018-04-06 07:35:44 +00:00
|
|
|
}
|
2018-02-16 11:18:15 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
case R.id.action_play_with_kodi:
|
2019-12-29 21:15:01 +00:00
|
|
|
/*try {
|
2018-02-16 11:18:15 +00:00
|
|
|
NavigationHelper.playWithKore(activity, Uri.parse(
|
|
|
|
url.replace("https", "http")));
|
|
|
|
} catch (Exception e) {
|
2018-09-02 23:22:59 +00:00
|
|
|
if (DEBUG) Log.i(TAG, "Failed to start kore", e);
|
2018-02-16 11:18:15 +00:00
|
|
|
showInstallKoreDialog(activity);
|
2019-12-29 21:15:01 +00:00
|
|
|
}*/
|
2018-02-16 11:18:15 +00:00
|
|
|
return true;
|
|
|
|
default:
|
|
|
|
return super.onOptionsItemSelected(item);
|
|
|
|
}
|
2017-03-31 18:15:26 +00:00
|
|
|
}
|
|
|
|
|
2019-12-29 21:15:01 +00:00
|
|
|
/*private static void showInstallKoreDialog(final Context context) {
|
2017-10-30 20:15:06 +00:00
|
|
|
final AlertDialog.Builder builder = new AlertDialog.Builder(context);
|
|
|
|
builder.setMessage(R.string.kore_not_found)
|
2018-02-11 20:34:32 +00:00
|
|
|
.setPositiveButton(R.string.install, (DialogInterface dialog, int which) ->
|
|
|
|
NavigationHelper.installKore(context))
|
2018-09-02 23:22:59 +00:00
|
|
|
.setNegativeButton(R.string.cancel, (DialogInterface dialog, int which) -> {
|
|
|
|
});
|
2017-10-30 20:15:06 +00:00
|
|
|
builder.create().show();
|
|
|
|
}
|
|
|
|
|
2018-02-16 11:18:15 +00:00
|
|
|
private void setupActionBarOnError(final String url) {
|
|
|
|
if (DEBUG) Log.d(TAG, "setupActionBarHandlerOnError() called with: url = [" + url + "]");
|
|
|
|
Log.e("-----", "missing code");
|
2019-12-29 21:15:01 +00:00
|
|
|
}*/
|
2018-02-16 11:18:15 +00:00
|
|
|
|
|
|
|
private void setupActionBar(final StreamInfo info) {
|
2017-09-03 06:04:18 +00:00
|
|
|
if (DEBUG) Log.d(TAG, "setupActionBarHandler() called with: info = [" + info + "]");
|
2018-02-16 11:18:15 +00:00
|
|
|
boolean isExternalPlayerEnabled = PreferenceManager.getDefaultSharedPreferences(activity)
|
|
|
|
.getBoolean(activity.getString(R.string.use_external_video_player_key), false);
|
2018-04-08 11:08:19 +00:00
|
|
|
|
2019-01-31 12:24:02 +00:00
|
|
|
sortedVideoStreams = ListHelper.getSortedStreamVideosList(
|
|
|
|
activity,
|
|
|
|
info.getVideoStreams(),
|
|
|
|
info.getVideoOnlyStreams(),
|
|
|
|
false);
|
2018-04-08 11:08:19 +00:00
|
|
|
selectedVideoStreamIndex = ListHelper.getDefaultResolutionIndex(activity, sortedVideoStreams);
|
|
|
|
|
2019-12-29 21:15:01 +00:00
|
|
|
/*final StreamItemAdapter<VideoStream, Stream> streamsAdapter =
|
2019-01-31 12:24:02 +00:00
|
|
|
new StreamItemAdapter<>(activity,
|
|
|
|
new StreamSizeWrapper<>(sortedVideoStreams, activity), isExternalPlayerEnabled);
|
2019-12-29 21:15:01 +00:00
|
|
|
|
2018-04-08 11:08:19 +00:00
|
|
|
spinnerToolbar.setAdapter(streamsAdapter);
|
|
|
|
spinnerToolbar.setSelection(selectedVideoStreamIndex);
|
2018-02-16 11:18:15 +00:00
|
|
|
spinnerToolbar.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
|
|
|
|
@Override
|
|
|
|
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
|
2018-04-08 11:08:19 +00:00
|
|
|
selectedVideoStreamIndex = position;
|
2018-02-16 11:18:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onNothingSelected(AdapterView<?> parent) {
|
2017-03-31 18:15:26 +00:00
|
|
|
}
|
2019-12-29 21:15:01 +00:00
|
|
|
});*/
|
2017-03-31 18:15:26 +00:00
|
|
|
}
|
|
|
|
|
2017-04-09 17:34:00 +00:00
|
|
|
/*//////////////////////////////////////////////////////////////////////////
|
|
|
|
// OwnStack
|
|
|
|
//////////////////////////////////////////////////////////////////////////*/
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Stack that contains the "navigation history".<br>
|
|
|
|
* The peek is the current video.
|
|
|
|
*/
|
2018-08-28 18:02:25 +00:00
|
|
|
protected final LinkedList<StackItem> stack = new LinkedList<>();
|
2017-04-09 17:34:00 +00:00
|
|
|
|
2017-09-03 06:04:18 +00:00
|
|
|
public void setTitleToUrl(int serviceId, String videoUrl, String name) {
|
|
|
|
if (name != null && !name.isEmpty()) {
|
2017-04-26 19:32:04 +00:00
|
|
|
for (StackItem stackItem : stack) {
|
2018-02-16 10:31:25 +00:00
|
|
|
if (stack.peek().getServiceId() == serviceId
|
|
|
|
&& stackItem.getUrl().equals(videoUrl)) {
|
|
|
|
stackItem.setTitle(name);
|
|
|
|
}
|
2017-04-26 19:32:04 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-09-03 06:04:18 +00:00
|
|
|
@Override
|
|
|
|
public boolean onBackPressed() {
|
|
|
|
if (DEBUG) Log.d(TAG, "onBackPressed() called");
|
2019-12-29 21:15:01 +00:00
|
|
|
|
2020-01-06 10:39:01 +00:00
|
|
|
// If we are in fullscreen mode just exit from it via first back press
|
2019-12-29 21:15:01 +00:00
|
|
|
if (player != null && player.isInFullscreen()) {
|
|
|
|
player.onPause();
|
|
|
|
restoreDefaultOrientation();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2020-01-06 10:39:01 +00:00
|
|
|
// If we have something in history of played items we replay it here
|
|
|
|
if (player != null && player.getPlayQueue().previous()) {
|
|
|
|
return true;
|
|
|
|
}
|
2017-04-09 17:34:00 +00:00
|
|
|
// That means that we are on the start of the stack,
|
|
|
|
// return false to let the MainActivity handle the onBack
|
2019-12-29 21:15:01 +00:00
|
|
|
if (stack.size() <= 1) {
|
|
|
|
restoreDefaultOrientation();
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
2017-04-09 17:34:00 +00:00
|
|
|
// Remove top
|
|
|
|
stack.pop();
|
2017-09-03 06:04:18 +00:00
|
|
|
// Get stack item from the new top
|
2017-04-09 17:34:00 +00:00
|
|
|
StackItem peek = stack.peek();
|
2017-04-26 19:32:04 +00:00
|
|
|
|
2019-12-29 21:15:01 +00:00
|
|
|
hideMainPlayer();
|
|
|
|
|
|
|
|
setAutoplay(false);
|
|
|
|
selectAndLoadVideo(
|
|
|
|
peek.getServiceId(),
|
2019-01-31 12:24:02 +00:00
|
|
|
peek.getUrl(),
|
2019-12-29 21:15:01 +00:00
|
|
|
!TextUtils.isEmpty(peek.getTitle()) ? peek.getTitle() : "",
|
|
|
|
peek.getPlayQueue());
|
|
|
|
|
2017-04-09 17:34:00 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2017-03-31 18:15:26 +00:00
|
|
|
/*//////////////////////////////////////////////////////////////////////////
|
2017-09-03 06:04:18 +00:00
|
|
|
// Info loading and handling
|
2017-03-31 18:15:26 +00:00
|
|
|
//////////////////////////////////////////////////////////////////////////*/
|
|
|
|
|
2017-09-03 06:04:18 +00:00
|
|
|
@Override
|
|
|
|
protected void doInitialLoadLogic() {
|
2019-12-29 21:15:01 +00:00
|
|
|
if (wasCleared()) return;
|
|
|
|
|
2017-09-03 06:04:18 +00:00
|
|
|
if (currentInfo == null) prepareAndLoadInfo();
|
|
|
|
else prepareAndHandleInfo(currentInfo, false);
|
2017-03-31 18:15:26 +00:00
|
|
|
}
|
|
|
|
|
2019-12-29 21:15:01 +00:00
|
|
|
public void selectAndLoadVideo(int serviceId, String videoUrl, String name, PlayQueue playQueue) {
|
2020-01-06 10:39:01 +00:00
|
|
|
boolean streamIsTheSame = this.playQueue != null && this.playQueue.equals(playQueue);
|
2019-12-29 21:15:01 +00:00
|
|
|
// Situation when user switches from players to main player. All needed data is here, we can start watching
|
|
|
|
if (streamIsTheSame) {
|
2020-01-06 10:39:01 +00:00
|
|
|
//TODO not sure about usefulness of this line in the case when user switches from one player to another
|
|
|
|
// handleResult(currentInfo);
|
2019-12-29 21:15:01 +00:00
|
|
|
openVideoPlayer();
|
|
|
|
return;
|
|
|
|
}
|
2020-01-06 10:39:01 +00:00
|
|
|
setInitialData(serviceId, videoUrl, name, playQueue);
|
2019-12-29 21:15:01 +00:00
|
|
|
startLoading(false);
|
2017-04-09 17:34:00 +00:00
|
|
|
}
|
|
|
|
|
2017-09-03 06:04:18 +00:00
|
|
|
public void prepareAndHandleInfo(final StreamInfo info, boolean scrollToTop) {
|
2019-01-31 12:24:02 +00:00
|
|
|
if (DEBUG) Log.d(TAG, "prepareAndHandleInfo() called with: info = ["
|
|
|
|
+ info + "], scrollToTop = [" + scrollToTop + "]");
|
2017-04-28 03:58:50 +00:00
|
|
|
|
2017-09-03 06:04:18 +00:00
|
|
|
showLoading();
|
2018-10-02 15:09:16 +00:00
|
|
|
initTabs();
|
2017-04-26 19:32:04 +00:00
|
|
|
|
2019-12-31 16:06:39 +00:00
|
|
|
if (scrollToTop) scrollToTop();
|
2018-12-19 05:28:59 +00:00
|
|
|
handleResult(info);
|
|
|
|
showContent();
|
|
|
|
|
2017-04-09 17:34:00 +00:00
|
|
|
}
|
2017-03-31 18:15:26 +00:00
|
|
|
|
2017-09-03 06:04:18 +00:00
|
|
|
protected void prepareAndLoadInfo() {
|
2019-12-31 16:06:39 +00:00
|
|
|
scrollToTop();
|
2017-09-03 06:04:18 +00:00
|
|
|
startLoading(false);
|
|
|
|
}
|
2017-04-28 03:58:50 +00:00
|
|
|
|
2017-09-03 06:04:18 +00:00
|
|
|
@Override
|
|
|
|
public void startLoading(boolean forceLoad) {
|
|
|
|
super.startLoading(forceLoad);
|
|
|
|
|
2018-10-02 15:09:16 +00:00
|
|
|
initTabs();
|
2017-09-03 06:04:18 +00:00
|
|
|
currentInfo = null;
|
|
|
|
if (currentWorker != null) currentWorker.dispose();
|
|
|
|
|
|
|
|
currentWorker = ExtractorHelper.getStreamInfo(serviceId, url, forceLoad)
|
|
|
|
.subscribeOn(Schedulers.io())
|
|
|
|
.observeOn(AndroidSchedulers.mainThread())
|
2018-02-11 20:34:32 +00:00
|
|
|
.subscribe((@NonNull StreamInfo result) -> {
|
|
|
|
isLoading.set(false);
|
2019-12-29 21:15:01 +00:00
|
|
|
hideMainPlayer();
|
2018-02-11 20:34:32 +00:00
|
|
|
handleResult(result);
|
2018-12-19 05:28:59 +00:00
|
|
|
showContent();
|
2019-12-29 21:15:01 +00:00
|
|
|
if (isAutoplayEnabled()) openVideoPlayer();
|
2018-02-11 20:34:32 +00:00
|
|
|
}, (@NonNull Throwable throwable) -> {
|
|
|
|
isLoading.set(false);
|
|
|
|
onError(throwable);
|
2017-09-03 06:04:18 +00:00
|
|
|
});
|
2018-09-23 01:32:19 +00:00
|
|
|
|
2018-10-02 15:09:16 +00:00
|
|
|
}
|
2018-09-23 01:32:19 +00:00
|
|
|
|
2018-10-02 15:09:16 +00:00
|
|
|
private void initTabs() {
|
2019-03-24 01:01:28 +00:00
|
|
|
if (pageAdapter.getCount() != 0) {
|
|
|
|
selectedTabTag = pageAdapter.getItemTitle(viewPager.getCurrentItem());
|
|
|
|
}
|
2018-10-02 15:09:16 +00:00
|
|
|
pageAdapter.clearAllItems();
|
|
|
|
|
|
|
|
if(shouldShowComments()){
|
|
|
|
pageAdapter.addFragment(CommentsFragment.getInstance(serviceId, url, name), COMMENTS_TAB_TAG);
|
|
|
|
}
|
|
|
|
|
2018-12-08 21:51:55 +00:00
|
|
|
if(showRelatedStreams && null == relatedStreamsLayout){
|
2018-10-02 15:26:14 +00:00
|
|
|
//temp empty fragment. will be updated in handleResult
|
2018-10-02 15:09:16 +00:00
|
|
|
pageAdapter.addFragment(new Fragment(), RELATED_TAB_TAG);
|
|
|
|
}
|
|
|
|
|
2019-03-03 12:50:15 +00:00
|
|
|
if(pageAdapter.getCount() == 0){
|
|
|
|
pageAdapter.addFragment(new EmptyFragment(), EMPTY_TAB_TAG);
|
|
|
|
}
|
|
|
|
|
2018-10-02 16:00:11 +00:00
|
|
|
pageAdapter.notifyDataSetUpdate();
|
|
|
|
|
2018-10-02 15:09:16 +00:00
|
|
|
if(pageAdapter.getCount() < 2){
|
|
|
|
tabLayout.setVisibility(View.GONE);
|
2018-10-02 15:26:14 +00:00
|
|
|
}else{
|
2019-03-24 01:01:28 +00:00
|
|
|
int position = pageAdapter.getItemPositionByTitle(selectedTabTag);
|
|
|
|
if(position != -1) viewPager.setCurrentItem(position);
|
2018-10-02 15:26:14 +00:00
|
|
|
tabLayout.setVisibility(View.VISIBLE);
|
2018-10-02 15:09:16 +00:00
|
|
|
}
|
2018-09-23 01:32:19 +00:00
|
|
|
}
|
|
|
|
|
2018-10-02 15:09:16 +00:00
|
|
|
private boolean shouldShowComments() {
|
|
|
|
try {
|
2019-02-15 19:53:26 +00:00
|
|
|
return showComments && NewPipe.getService(serviceId)
|
|
|
|
.getServiceInfo()
|
|
|
|
.getMediaCapabilities()
|
|
|
|
.contains(COMMENTS);
|
2018-10-02 15:09:16 +00:00
|
|
|
} catch (ExtractionException e) {
|
|
|
|
return false;
|
2018-09-23 01:32:19 +00:00
|
|
|
}
|
2017-09-03 06:04:18 +00:00
|
|
|
}
|
2017-04-28 03:58:50 +00:00
|
|
|
|
2019-12-31 16:06:39 +00:00
|
|
|
public void scrollToTop() {
|
|
|
|
appBarLayout.setExpanded(true, true);
|
|
|
|
}
|
|
|
|
|
2017-09-03 06:04:18 +00:00
|
|
|
/*//////////////////////////////////////////////////////////////////////////
|
|
|
|
// Play Utils
|
|
|
|
//////////////////////////////////////////////////////////////////////////*/
|
2017-04-09 17:34:00 +00:00
|
|
|
|
2017-10-13 00:02:07 +00:00
|
|
|
private void openBackgroundPlayer(final boolean append) {
|
2018-02-16 10:31:25 +00:00
|
|
|
AudioStream audioStream = currentInfo.getAudioStreams()
|
|
|
|
.get(ListHelper.getDefaultAudioFormat(activity, currentInfo.getAudioStreams()));
|
2017-03-31 18:15:26 +00:00
|
|
|
|
2017-09-03 06:04:18 +00:00
|
|
|
boolean useExternalAudioPlayer = PreferenceManager.getDefaultSharedPreferences(activity)
|
|
|
|
.getBoolean(activity.getString(R.string.use_external_audio_player_key), false);
|
2017-04-28 03:58:50 +00:00
|
|
|
|
2019-12-31 02:07:07 +00:00
|
|
|
// If a user watched video inside fullscreen mode and than chose another player return to non-fullscreen mode
|
|
|
|
if (player != null && player.isInFullscreen()) player.toggleFullscreen();
|
|
|
|
|
2017-09-03 06:04:18 +00:00
|
|
|
if (!useExternalAudioPlayer && android.os.Build.VERSION.SDK_INT >= 16) {
|
2017-10-13 00:02:07 +00:00
|
|
|
openNormalBackgroundPlayer(append);
|
2017-04-26 19:32:04 +00:00
|
|
|
} else {
|
2018-06-19 01:27:30 +00:00
|
|
|
startOnExternalPlayer(activity, currentInfo, audioStream);
|
2017-04-26 19:32:04 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-10-13 00:02:07 +00:00
|
|
|
private void openPopupPlayer(final boolean append) {
|
2018-01-04 06:53:31 +00:00
|
|
|
if (!PermissionHelper.isPopupEnabled(activity)) {
|
|
|
|
PermissionHelper.showPopupEnablementToast(activity);
|
2017-09-03 06:04:18 +00:00
|
|
|
return;
|
|
|
|
}
|
2017-04-26 19:32:04 +00:00
|
|
|
|
2019-12-29 21:15:01 +00:00
|
|
|
// See UI changes while remote playQueue changes
|
|
|
|
if (!bounded) startService(false);
|
|
|
|
|
2019-12-31 02:07:07 +00:00
|
|
|
// If a user watched video inside fullscreen mode and than chose another player return to non-fullscreen mode
|
|
|
|
if (player != null && player.isInFullscreen()) player.toggleFullscreen();
|
|
|
|
|
2019-12-29 21:15:01 +00:00
|
|
|
PlayQueue queue = setupPlayQueueForIntent(append);
|
2017-10-13 00:02:07 +00:00
|
|
|
if (append) {
|
2019-12-29 21:15:01 +00:00
|
|
|
NavigationHelper.enqueueOnPopupPlayer(activity, queue, false);
|
2017-10-13 00:02:07 +00:00
|
|
|
} else {
|
2019-12-29 21:15:01 +00:00
|
|
|
NavigationHelper.playOnPopupPlayer(activity, queue, true);
|
2017-10-13 00:02:07 +00:00
|
|
|
}
|
2017-09-03 06:04:18 +00:00
|
|
|
}
|
2017-04-26 19:32:04 +00:00
|
|
|
|
2017-09-03 06:04:18 +00:00
|
|
|
private void openVideoPlayer() {
|
2018-02-16 10:31:25 +00:00
|
|
|
if (PreferenceManager.getDefaultSharedPreferences(activity)
|
|
|
|
.getBoolean(this.getString(R.string.use_external_video_player_key), false)) {
|
2019-12-29 21:15:01 +00:00
|
|
|
VideoStream selectedVideoStream = getSelectedVideoStream();
|
2018-06-19 01:27:30 +00:00
|
|
|
startOnExternalPlayer(activity, currentInfo, selectedVideoStream);
|
2017-04-26 19:32:04 +00:00
|
|
|
} else {
|
2018-11-13 16:27:47 +00:00
|
|
|
openNormalPlayer();
|
2017-04-26 19:32:04 +00:00
|
|
|
}
|
2017-09-03 06:04:18 +00:00
|
|
|
}
|
2017-04-26 19:32:04 +00:00
|
|
|
|
2017-10-13 00:02:07 +00:00
|
|
|
private void openNormalBackgroundPlayer(final boolean append) {
|
2019-12-29 21:15:01 +00:00
|
|
|
// See UI changes while remote playQueue changes
|
|
|
|
if (!bounded) startService(false);
|
|
|
|
|
|
|
|
PlayQueue queue = setupPlayQueueForIntent(append);
|
2017-10-14 04:07:19 +00:00
|
|
|
if (append) {
|
2019-12-29 21:15:01 +00:00
|
|
|
NavigationHelper.enqueueOnBackgroundPlayer(activity, queue, false);
|
2017-10-14 04:07:19 +00:00
|
|
|
} else {
|
2019-12-29 21:15:01 +00:00
|
|
|
NavigationHelper.playOnBackgroundPlayer(activity, queue, true);
|
2017-10-14 04:07:19 +00:00
|
|
|
}
|
2017-09-03 06:04:18 +00:00
|
|
|
}
|
2017-04-26 19:32:04 +00:00
|
|
|
|
2018-11-13 16:27:47 +00:00
|
|
|
private void openNormalPlayer() {
|
2019-12-29 21:15:01 +00:00
|
|
|
if (playerService == null) {
|
|
|
|
startService(true);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (currentInfo == null || playQueue == null)
|
|
|
|
return;
|
|
|
|
|
|
|
|
PlayQueue queue = setupPlayQueueForIntent(false);
|
|
|
|
|
|
|
|
addVideoPlayerView();
|
|
|
|
playerService.getView().setVisibility(View.GONE);
|
|
|
|
|
|
|
|
Intent playerIntent = NavigationHelper.getPlayerIntent(
|
|
|
|
getContext(), MainPlayer.class, queue, null, true);
|
|
|
|
activity.startService(playerIntent);
|
|
|
|
}
|
|
|
|
|
|
|
|
private void hideMainPlayer() {
|
|
|
|
if (playerService == null || playerService.getView() == null || !player.videoPlayerSelected())
|
|
|
|
return;
|
|
|
|
|
|
|
|
removeVideoPlayerView();
|
|
|
|
playerService.stop();
|
|
|
|
playerService.getView().setVisibility(View.GONE);
|
|
|
|
}
|
|
|
|
|
|
|
|
private PlayQueue setupPlayQueueForIntent(boolean append) {
|
|
|
|
if (append) return new SinglePlayQueue(currentInfo);
|
|
|
|
|
|
|
|
PlayQueue queue = playQueue;
|
|
|
|
// Size can be 0 because queue removes bad stream automatically when error occurs
|
|
|
|
if (playQueue == null || playQueue.size() == 0)
|
|
|
|
queue = new SinglePlayQueue(currentInfo);
|
|
|
|
this.playQueue = queue;
|
|
|
|
|
|
|
|
return queue;
|
|
|
|
}
|
|
|
|
|
|
|
|
private void openChannel() {
|
|
|
|
if (TextUtils.isEmpty(currentInfo.getUploaderUrl())) {
|
|
|
|
Log.w(TAG, "Can't open channel because we got no channel URL");
|
|
|
|
} else {
|
|
|
|
try {
|
|
|
|
NavigationHelper.openChannelFragment(
|
|
|
|
getFragmentManager(),
|
|
|
|
currentInfo.getServiceId(),
|
|
|
|
currentInfo.getUploaderUrl(),
|
|
|
|
currentInfo.getUploaderName());
|
|
|
|
} catch (Exception e) {
|
|
|
|
ErrorActivity.reportUiError((AppCompatActivity) getActivity(), e);
|
|
|
|
}
|
|
|
|
}
|
2017-06-15 14:26:48 +00:00
|
|
|
}
|
2017-06-28 01:39:33 +00:00
|
|
|
|
2017-09-03 06:04:18 +00:00
|
|
|
/*//////////////////////////////////////////////////////////////////////////
|
|
|
|
// Utils
|
|
|
|
//////////////////////////////////////////////////////////////////////////*/
|
|
|
|
|
|
|
|
public void setAutoplay(boolean autoplay) {
|
|
|
|
this.autoPlayEnabled = autoplay;
|
2017-03-31 18:15:26 +00:00
|
|
|
}
|
|
|
|
|
2018-06-19 01:27:30 +00:00
|
|
|
private void startOnExternalPlayer(@NonNull final Context context,
|
|
|
|
@NonNull final StreamInfo info,
|
|
|
|
@NonNull final Stream selectedStream) {
|
|
|
|
NavigationHelper.playOnExternalPlayer(context, currentInfo.getName(),
|
|
|
|
currentInfo.getUploaderName(), selectedStream);
|
|
|
|
|
|
|
|
final HistoryRecordManager recordManager = new HistoryRecordManager(requireContext());
|
|
|
|
disposables.add(recordManager.onViewed(info).onErrorComplete()
|
|
|
|
.subscribe(
|
|
|
|
ignored -> {/* successful */},
|
|
|
|
error -> Log.e(TAG, "Register view failure: ", error)
|
|
|
|
));
|
|
|
|
}
|
|
|
|
|
2019-12-29 21:15:01 +00:00
|
|
|
private boolean isExternalPlayerEnabled() {
|
|
|
|
return PreferenceManager.getDefaultSharedPreferences(getContext())
|
|
|
|
.getBoolean(getString(R.string.use_external_video_player_key), false);
|
|
|
|
}
|
|
|
|
|
|
|
|
// This method overrides default behaviour when setAutoplay() is called.
|
|
|
|
// Don't auto play if the user selected an external player
|
|
|
|
private boolean isAutoplayEnabled() {
|
|
|
|
return playQueue != null && playQueue.getStreams().size() != 0 && !isExternalPlayerEnabled() && autoPlayEnabled;
|
|
|
|
}
|
|
|
|
|
|
|
|
private void addVideoPlayerView() {
|
|
|
|
if (player == null) return;
|
|
|
|
|
|
|
|
FrameLayout viewHolder = getView().findViewById(R.id.player_placeholder);
|
|
|
|
|
|
|
|
// Check if viewHolder already contains a child
|
|
|
|
if (player.getRootView() != viewHolder) removeVideoPlayerView();
|
2019-12-31 02:07:07 +00:00
|
|
|
setHeightThumbnail();
|
2019-12-29 21:15:01 +00:00
|
|
|
|
|
|
|
// Prevent from re-adding a view multiple times
|
|
|
|
if (player.getRootView().getParent() == null) viewHolder.addView(player.getRootView());
|
|
|
|
}
|
|
|
|
|
|
|
|
private void removeVideoPlayerView() {
|
|
|
|
makeDefaultHeightForVideoPlaceholder();
|
|
|
|
|
|
|
|
playerService.removeViewFromParent();
|
|
|
|
}
|
|
|
|
|
|
|
|
private void makeDefaultHeightForVideoPlaceholder() {
|
|
|
|
FrameLayout viewHolder = getView().findViewById(R.id.player_placeholder);
|
|
|
|
viewHolder.getLayoutParams().height = FrameLayout.LayoutParams.MATCH_PARENT;
|
|
|
|
viewHolder.requestLayout();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-04-08 11:08:19 +00:00
|
|
|
@Nullable
|
2017-08-12 04:50:25 +00:00
|
|
|
private VideoStream getSelectedVideoStream() {
|
2018-04-08 11:08:19 +00:00
|
|
|
return sortedVideoStreams != null ? sortedVideoStreams.get(selectedVideoStreamIndex) : null;
|
2017-08-12 04:50:25 +00:00
|
|
|
}
|
|
|
|
|
2017-09-03 06:04:18 +00:00
|
|
|
private void prepareDescription(final String descriptionHtml) {
|
|
|
|
if (TextUtils.isEmpty(descriptionHtml)) {
|
|
|
|
return;
|
2017-08-12 04:50:25 +00:00
|
|
|
}
|
2017-03-31 18:15:26 +00:00
|
|
|
|
2017-09-03 06:04:18 +00:00
|
|
|
disposables.add(Single.just(descriptionHtml)
|
2018-02-11 20:34:32 +00:00
|
|
|
.map((@io.reactivex.annotations.NonNull String description) -> {
|
2018-02-16 10:31:25 +00:00
|
|
|
Spanned parsedDescription;
|
|
|
|
if (Build.VERSION.SDK_INT >= 24) {
|
|
|
|
parsedDescription = Html.fromHtml(description, 0);
|
|
|
|
} else {
|
|
|
|
//noinspection deprecation
|
|
|
|
parsedDescription = Html.fromHtml(description);
|
|
|
|
}
|
|
|
|
return parsedDescription;
|
2017-09-03 06:04:18 +00:00
|
|
|
})
|
|
|
|
.subscribeOn(Schedulers.computation())
|
|
|
|
.observeOn(AndroidSchedulers.mainThread())
|
2018-02-11 20:34:32 +00:00
|
|
|
.subscribe((@io.reactivex.annotations.NonNull Spanned spanned) -> {
|
2018-02-16 10:31:25 +00:00
|
|
|
videoDescriptionView.setText(spanned);
|
|
|
|
videoDescriptionView.setVisibility(View.VISIBLE);
|
2017-09-03 06:04:18 +00:00
|
|
|
}));
|
2017-03-31 18:15:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
private void setHeightThumbnail() {
|
2017-09-03 06:04:18 +00:00
|
|
|
final DisplayMetrics metrics = getResources().getDisplayMetrics();
|
|
|
|
boolean isPortrait = metrics.heightPixels > metrics.widthPixels;
|
2019-12-31 02:07:07 +00:00
|
|
|
|
|
|
|
int height;
|
|
|
|
if (player != null && player.isInFullscreen())
|
2020-01-03 05:05:31 +00:00
|
|
|
height = isInMultiWindow() ? getView().getHeight() : activity.getWindow().getDecorView().getHeight();
|
2019-12-31 02:07:07 +00:00
|
|
|
else
|
|
|
|
height = isPortrait
|
|
|
|
? (int) (metrics.widthPixels / (16.0f / 9.0f))
|
|
|
|
: (int) (metrics.heightPixels / 2f);;
|
|
|
|
|
2018-02-16 10:31:25 +00:00
|
|
|
thumbnailImageView.setLayoutParams(
|
|
|
|
new FrameLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, height));
|
2017-03-31 18:15:26 +00:00
|
|
|
thumbnailImageView.setMinimumHeight(height);
|
|
|
|
}
|
|
|
|
|
2018-12-19 05:28:59 +00:00
|
|
|
private void showContent() {
|
2019-08-07 10:00:47 +00:00
|
|
|
contentRootLayoutHiding.setVisibility(View.VISIBLE);
|
2017-04-28 03:58:50 +00:00
|
|
|
}
|
2017-03-31 18:15:26 +00:00
|
|
|
|
2019-12-29 21:15:01 +00:00
|
|
|
protected void setInitialData(int serviceId, String url, String name, PlayQueue playQueue) {
|
2017-09-03 06:04:18 +00:00
|
|
|
this.serviceId = serviceId;
|
|
|
|
this.url = url;
|
|
|
|
this.name = !TextUtils.isEmpty(name) ? name : "";
|
2019-12-29 21:15:01 +00:00
|
|
|
this.playQueue = playQueue;
|
2017-09-03 06:04:18 +00:00
|
|
|
}
|
|
|
|
|
2017-04-26 19:32:04 +00:00
|
|
|
private void setErrorImage(final int imageResource) {
|
|
|
|
if (thumbnailImageView == null || activity == null) return;
|
2017-09-03 06:04:18 +00:00
|
|
|
|
2017-04-26 19:32:04 +00:00
|
|
|
thumbnailImageView.setImageDrawable(ContextCompat.getDrawable(activity, imageResource));
|
2018-02-16 10:31:25 +00:00
|
|
|
animateView(thumbnailImageView, false, 0, 0,
|
|
|
|
() -> animateView(thumbnailImageView, true, 500));
|
2017-04-26 19:32:04 +00:00
|
|
|
}
|
2017-03-31 18:15:26 +00:00
|
|
|
|
2017-04-26 19:32:04 +00:00
|
|
|
@Override
|
2017-09-03 06:04:18 +00:00
|
|
|
public void showError(String message, boolean showRetryButton) {
|
|
|
|
showError(message, showRetryButton, R.drawable.not_available_monkey);
|
|
|
|
}
|
2017-03-31 18:15:26 +00:00
|
|
|
|
2017-09-03 06:04:18 +00:00
|
|
|
protected void showError(String message, boolean showRetryButton, @DrawableRes int imageError) {
|
|
|
|
super.showError(message, showRetryButton);
|
|
|
|
setErrorImage(imageError);
|
2017-04-26 19:32:04 +00:00
|
|
|
}
|
2017-03-31 18:15:26 +00:00
|
|
|
|
2019-12-29 21:15:01 +00:00
|
|
|
private void setupBroadcastReceiver() {
|
|
|
|
broadcastReceiver = new BroadcastReceiver() {
|
|
|
|
@Override
|
|
|
|
public void onReceive(Context context, Intent intent) {
|
|
|
|
if(intent.getAction().equals(ACTION_SHOW_MAIN_PLAYER)) {
|
|
|
|
bottomSheetBehavior.setState(BottomSheetBehavior.STATE_EXPANDED);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
IntentFilter intentFilter = new IntentFilter(ACTION_SHOW_MAIN_PLAYER);
|
|
|
|
getActivity().registerReceiver(broadcastReceiver, intentFilter);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*//////////////////////////////////////////////////////////////////////////
|
|
|
|
// Orientation listener
|
|
|
|
//////////////////////////////////////////////////////////////////////////*/
|
|
|
|
|
|
|
|
private boolean globalScreenOrientationLocked() {
|
|
|
|
// 1: Screen orientation changes using accelerometer
|
|
|
|
// 0: Screen orientation is locked
|
|
|
|
return !(android.provider.Settings.System.getInt(
|
|
|
|
getContext().getContentResolver(), Settings.System.ACCELEROMETER_ROTATION, 0) == 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
private void restoreDefaultOrientation() {
|
|
|
|
if (player == null || !player.videoPlayerSelected()) return;
|
|
|
|
|
|
|
|
if (player != null && player.isInFullscreen()) player.toggleFullscreen();
|
|
|
|
// This will show systemUI and pause the player.
|
|
|
|
// User can tap on Play button and video will be in fullscreen mode again
|
|
|
|
if (globalScreenOrientationLocked()) removeVideoPlayerView();
|
|
|
|
getActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
|
|
|
|
}
|
|
|
|
|
|
|
|
private void setupOrientation() {
|
|
|
|
if (player == null || !player.videoPlayerSelected()) return;
|
|
|
|
|
|
|
|
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(getActivity());
|
|
|
|
int newOrientation;
|
|
|
|
if (globalScreenOrientationLocked()) {
|
|
|
|
boolean lastOrientationWasLandscape
|
|
|
|
= sharedPreferences.getBoolean(getString(R.string.last_orientation_landscape_key), false);
|
|
|
|
newOrientation = lastOrientationWasLandscape
|
|
|
|
? ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE
|
|
|
|
: ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT;
|
|
|
|
} else
|
|
|
|
newOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
|
|
|
|
|
|
|
|
if (newOrientation != getActivity().getRequestedOrientation())
|
|
|
|
getActivity().setRequestedOrientation(newOrientation);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onSettingsChanged() {
|
|
|
|
if(!globalScreenOrientationLocked())
|
|
|
|
getActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
|
|
|
|
}
|
|
|
|
|
2017-06-28 01:39:33 +00:00
|
|
|
/*//////////////////////////////////////////////////////////////////////////
|
2017-09-03 06:04:18 +00:00
|
|
|
// Contract
|
2017-06-28 01:39:33 +00:00
|
|
|
//////////////////////////////////////////////////////////////////////////*/
|
|
|
|
|
2017-04-26 19:32:04 +00:00
|
|
|
@Override
|
2017-09-03 06:04:18 +00:00
|
|
|
public void showLoading() {
|
2019-08-07 10:00:47 +00:00
|
|
|
|
2017-09-03 06:04:18 +00:00
|
|
|
super.showLoading();
|
2017-04-09 17:34:00 +00:00
|
|
|
|
2019-08-07 10:00:47 +00:00
|
|
|
//if data is already cached, transition from VISIBLE -> INVISIBLE -> VISIBLE is not required
|
|
|
|
if(!ExtractorHelper.isCached(serviceId, url, InfoItem.InfoType.STREAM)){
|
|
|
|
contentRootLayoutHiding.setVisibility(View.INVISIBLE);
|
|
|
|
}
|
|
|
|
|
2019-12-29 21:15:01 +00:00
|
|
|
//animateView(spinnerToolbar, false, 200);
|
2017-09-03 06:04:18 +00:00
|
|
|
animateView(thumbnailPlayButton, false, 50);
|
2018-03-10 16:16:51 +00:00
|
|
|
animateView(detailDurationView, false, 100);
|
2019-04-13 07:31:32 +00:00
|
|
|
animateView(detailPositionView, false, 100);
|
|
|
|
animateView(positionView, false, 50);
|
2017-03-31 18:15:26 +00:00
|
|
|
|
2017-09-03 06:04:18 +00:00
|
|
|
videoTitleTextView.setText(name != null ? name : "");
|
|
|
|
videoTitleTextView.setMaxLines(1);
|
|
|
|
animateView(videoTitleTextView, true, 0);
|
2017-04-26 19:32:04 +00:00
|
|
|
|
2017-09-03 06:04:18 +00:00
|
|
|
videoDescriptionRootLayout.setVisibility(View.GONE);
|
2018-12-08 21:51:55 +00:00
|
|
|
videoTitleToggleArrow.setImageResource(R.drawable.arrow_down);
|
|
|
|
videoTitleToggleArrow.setVisibility(View.GONE);
|
2017-09-03 06:04:18 +00:00
|
|
|
videoTitleRoot.setClickable(false);
|
2017-03-31 18:15:26 +00:00
|
|
|
|
2018-12-08 21:51:55 +00:00
|
|
|
if(relatedStreamsLayout != null){
|
|
|
|
if(showRelatedStreams){
|
|
|
|
relatedStreamsLayout.setVisibility(View.INVISIBLE);
|
|
|
|
}else{
|
|
|
|
relatedStreamsLayout.setVisibility(View.GONE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-09-03 06:04:18 +00:00
|
|
|
imageLoader.cancelDisplayTask(thumbnailImageView);
|
|
|
|
imageLoader.cancelDisplayTask(uploaderThumb);
|
|
|
|
thumbnailImageView.setImageBitmap(null);
|
|
|
|
uploaderThumb.setImageBitmap(null);
|
2017-03-31 18:15:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2017-09-03 06:04:18 +00:00
|
|
|
public void handleResult(@NonNull StreamInfo info) {
|
|
|
|
super.handleResult(info);
|
2017-04-26 19:32:04 +00:00
|
|
|
|
2019-12-29 21:15:01 +00:00
|
|
|
currentInfo = info;
|
|
|
|
setInitialData(info.getServiceId(), info.getOriginalUrl(), info.getName(),
|
|
|
|
playQueue == null ? new SinglePlayQueue(info) : playQueue);
|
|
|
|
|
2018-10-02 15:09:16 +00:00
|
|
|
if(showRelatedStreams){
|
2018-12-08 21:51:55 +00:00
|
|
|
if(null == relatedStreamsLayout){ //phone
|
2019-12-29 21:15:01 +00:00
|
|
|
pageAdapter.updateItem(RELATED_TAB_TAG, RelatedVideosFragment.getInstance(info));
|
2018-12-08 21:51:55 +00:00
|
|
|
pageAdapter.notifyDataSetUpdate();
|
|
|
|
}else{ //tablet
|
|
|
|
getChildFragmentManager().beginTransaction()
|
2019-12-29 21:15:01 +00:00
|
|
|
.replace(R.id.relatedStreamsLayout, RelatedVideosFragment.getInstance(info))
|
2018-12-08 21:51:55 +00:00
|
|
|
.commitNow();
|
|
|
|
relatedStreamsLayout.setVisibility(View.VISIBLE);
|
|
|
|
}
|
2018-10-02 15:09:16 +00:00
|
|
|
}
|
|
|
|
|
2017-09-03 06:04:18 +00:00
|
|
|
animateView(thumbnailPlayButton, true, 200);
|
|
|
|
videoTitleTextView.setText(name);
|
2019-12-29 21:15:01 +00:00
|
|
|
overlayTitleTextView.setText(name);
|
2017-03-31 18:15:26 +00:00
|
|
|
|
2017-12-08 14:05:08 +00:00
|
|
|
if (!TextUtils.isEmpty(info.getUploaderName())) {
|
|
|
|
uploaderTextView.setText(info.getUploaderName());
|
|
|
|
uploaderTextView.setVisibility(View.VISIBLE);
|
2018-01-29 07:01:06 +00:00
|
|
|
uploaderTextView.setSelected(true);
|
2019-12-29 21:15:01 +00:00
|
|
|
overlayChannelTextView.setText(info.getUploaderName());
|
2017-12-08 14:05:08 +00:00
|
|
|
} else {
|
|
|
|
uploaderTextView.setVisibility(View.GONE);
|
|
|
|
}
|
2017-09-03 06:04:18 +00:00
|
|
|
uploaderThumb.setImageDrawable(ContextCompat.getDrawable(activity, R.drawable.buddy));
|
2017-03-31 18:15:26 +00:00
|
|
|
|
2017-12-08 14:05:08 +00:00
|
|
|
if (info.getViewCount() >= 0) {
|
2019-10-28 02:37:36 +00:00
|
|
|
if (info.getStreamType().equals(StreamType.AUDIO_LIVE_STREAM)) {
|
|
|
|
videoCountView.setText(Localization.listeningCount(activity, info.getViewCount()));
|
|
|
|
} else if (info.getStreamType().equals(StreamType.LIVE_STREAM)) {
|
|
|
|
videoCountView.setText(Localization.watchingCount(activity, info.getViewCount()));
|
|
|
|
} else {
|
|
|
|
videoCountView.setText(Localization.localizeViewCount(activity, info.getViewCount()));
|
|
|
|
}
|
2017-12-08 14:05:08 +00:00
|
|
|
videoCountView.setVisibility(View.VISIBLE);
|
|
|
|
} else {
|
|
|
|
videoCountView.setVisibility(View.GONE);
|
|
|
|
}
|
2017-03-31 18:15:26 +00:00
|
|
|
|
2017-12-08 14:05:08 +00:00
|
|
|
if (info.getDislikeCount() == -1 && info.getLikeCount() == -1) {
|
2017-09-03 06:04:18 +00:00
|
|
|
thumbsDownImageView.setVisibility(View.VISIBLE);
|
|
|
|
thumbsUpImageView.setVisibility(View.VISIBLE);
|
|
|
|
thumbsUpTextView.setVisibility(View.GONE);
|
|
|
|
thumbsDownTextView.setVisibility(View.GONE);
|
2017-04-12 06:07:15 +00:00
|
|
|
|
2017-09-03 06:04:18 +00:00
|
|
|
thumbsDisabledTextView.setVisibility(View.VISIBLE);
|
|
|
|
} else {
|
2017-12-08 14:05:08 +00:00
|
|
|
if (info.getDislikeCount() >= 0) {
|
|
|
|
thumbsDownTextView.setText(Localization.shortCount(activity, info.getDislikeCount()));
|
|
|
|
thumbsDownTextView.setVisibility(View.VISIBLE);
|
|
|
|
thumbsDownImageView.setVisibility(View.VISIBLE);
|
|
|
|
} else {
|
|
|
|
thumbsDownTextView.setVisibility(View.GONE);
|
|
|
|
thumbsDownImageView.setVisibility(View.GONE);
|
|
|
|
}
|
2017-06-28 01:39:33 +00:00
|
|
|
|
2017-12-08 14:05:08 +00: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 06:04:18 +00:00
|
|
|
thumbsDisabledTextView.setVisibility(View.GONE);
|
|
|
|
}
|
2017-06-15 14:26:48 +00:00
|
|
|
|
2018-03-10 16:16:51 +00:00
|
|
|
if (info.getDuration() > 0) {
|
|
|
|
detailDurationView.setText(Localization.getDurationString(info.getDuration()));
|
2019-01-31 12:24:02 +00:00
|
|
|
detailDurationView.setBackgroundColor(
|
|
|
|
ContextCompat.getColor(activity, R.color.duration_background_color));
|
2018-03-10 16:16:51 +00:00
|
|
|
animateView(detailDurationView, true, 100);
|
|
|
|
} else if (info.getStreamType() == StreamType.LIVE_STREAM) {
|
|
|
|
detailDurationView.setText(R.string.duration_live);
|
2019-01-31 12:24:02 +00:00
|
|
|
detailDurationView.setBackgroundColor(
|
|
|
|
ContextCompat.getColor(activity, R.color.live_duration_background_color));
|
2018-03-10 16:16:51 +00:00
|
|
|
animateView(detailDurationView, true, 100);
|
|
|
|
} else {
|
|
|
|
detailDurationView.setVisibility(View.GONE);
|
|
|
|
}
|
|
|
|
|
2017-09-03 06:04:18 +00:00
|
|
|
videoDescriptionView.setVisibility(View.GONE);
|
2018-12-08 21:51:55 +00:00
|
|
|
videoTitleRoot.setClickable(true);
|
|
|
|
videoTitleToggleArrow.setVisibility(View.VISIBLE);
|
|
|
|
videoTitleToggleArrow.setImageResource(R.drawable.arrow_down);
|
|
|
|
videoDescriptionRootLayout.setVisibility(View.GONE);
|
2019-10-28 02:35:51 +00:00
|
|
|
|
|
|
|
if (info.getUploadDate() != null) {
|
|
|
|
videoUploadDateView.setText(Localization.localizeUploadDate(activity, info.getUploadDate().date().getTime()));
|
|
|
|
videoUploadDateView.setVisibility(View.VISIBLE);
|
|
|
|
} else {
|
|
|
|
videoUploadDateView.setText(null);
|
|
|
|
videoUploadDateView.setVisibility(View.GONE);
|
2017-06-15 14:26:48 +00:00
|
|
|
}
|
2019-10-28 02:35:51 +00:00
|
|
|
|
2017-12-08 14:05:08 +00:00
|
|
|
prepareDescription(info.getDescription());
|
2019-04-13 07:31:32 +00:00
|
|
|
updateProgressInfo(info);
|
2017-06-15 14:26:48 +00:00
|
|
|
|
2019-12-29 21:15:01 +00:00
|
|
|
//animateView(spinnerToolbar, true, 500);
|
2018-02-16 11:18:15 +00:00
|
|
|
setupActionBar(info);
|
2017-09-03 06:04:18 +00:00
|
|
|
initThumbnailViews(info);
|
2018-04-06 07:35:44 +00:00
|
|
|
|
2017-12-08 14:05:08 +00:00
|
|
|
setTitleToUrl(info.getServiceId(), info.getUrl(), info.getName());
|
2018-04-06 07:35:44 +00:00
|
|
|
setTitleToUrl(info.getServiceId(), info.getOriginalUrl(), info.getName());
|
2017-06-15 14:26:48 +00:00
|
|
|
|
2017-12-08 14:05:08 +00:00
|
|
|
if (!info.getErrors().isEmpty()) {
|
2018-02-16 10:31:25 +00:00
|
|
|
showSnackBarError(info.getErrors(),
|
|
|
|
UserAction.REQUESTED_STREAM,
|
|
|
|
NewPipe.getNameOfService(info.getServiceId()),
|
|
|
|
info.getUrl(),
|
|
|
|
0);
|
2017-06-15 14:26:48 +00:00
|
|
|
}
|
|
|
|
|
2018-02-25 23:10:11 +00:00
|
|
|
switch (info.getStreamType()) {
|
|
|
|
case LIVE_STREAM:
|
|
|
|
case AUDIO_LIVE_STREAM:
|
|
|
|
detailControlsDownload.setVisibility(View.GONE);
|
|
|
|
spinnerToolbar.setVisibility(View.GONE);
|
|
|
|
break;
|
|
|
|
default:
|
2018-08-21 15:43:39 +00:00
|
|
|
if(info.getAudioStreams().isEmpty()) detailControlsBackground.setVisibility(View.GONE);
|
2018-03-18 15:37:49 +00:00
|
|
|
if (!info.getVideoStreams().isEmpty()
|
|
|
|
|| !info.getVideoOnlyStreams().isEmpty()) break;
|
2018-02-25 23:10:11 +00:00
|
|
|
|
|
|
|
detailControlsPopup.setVisibility(View.GONE);
|
|
|
|
spinnerToolbar.setVisibility(View.GONE);
|
|
|
|
thumbnailPlayButton.setImageResource(R.drawable.ic_headset_white_24dp);
|
|
|
|
break;
|
2017-09-14 08:49:39 +00:00
|
|
|
}
|
2017-06-15 14:26:48 +00:00
|
|
|
}
|
|
|
|
|
2018-04-07 17:32:02 +00:00
|
|
|
|
|
|
|
public void openDownloadDialog() {
|
2018-04-08 16:49:27 +00:00
|
|
|
try {
|
|
|
|
DownloadDialog downloadDialog = DownloadDialog.newInstance(currentInfo);
|
|
|
|
downloadDialog.setVideoStreams(sortedVideoStreams);
|
|
|
|
downloadDialog.setAudioStreams(currentInfo.getAudioStreams());
|
|
|
|
downloadDialog.setSelectedVideoStream(selectedVideoStreamIndex);
|
2018-09-23 18:12:23 +00:00
|
|
|
downloadDialog.setSubtitleStreams(currentInfo.getSubtitles());
|
2018-04-08 16:49:27 +00:00
|
|
|
|
2019-06-14 15:19:50 +00:00
|
|
|
downloadDialog.show(getActivity().getSupportFragmentManager(), "downloadDialog");
|
2018-04-08 16:49:27 +00:00
|
|
|
} catch (Exception e) {
|
2018-12-23 21:07:27 +00:00
|
|
|
ErrorActivity.ErrorInfo info = ErrorActivity.ErrorInfo.make(UserAction.UI_ERROR,
|
|
|
|
ServiceList.all()
|
|
|
|
.get(currentInfo
|
|
|
|
.getServiceId())
|
|
|
|
.getServiceInfo()
|
|
|
|
.getName(), "",
|
|
|
|
R.string.could_not_setup_download_menu);
|
|
|
|
|
|
|
|
ErrorActivity.reportError(getActivity(),
|
|
|
|
e,
|
|
|
|
getActivity().getClass(),
|
|
|
|
getActivity().findViewById(android.R.id.content), info);
|
2018-04-08 16:49:27 +00:00
|
|
|
}
|
2018-04-07 17:32:02 +00:00
|
|
|
}
|
|
|
|
|
2017-09-03 06:04:18 +00:00
|
|
|
/*//////////////////////////////////////////////////////////////////////////
|
|
|
|
// Stream Results
|
|
|
|
//////////////////////////////////////////////////////////////////////////*/
|
|
|
|
|
|
|
|
@Override
|
|
|
|
protected boolean onError(Throwable exception) {
|
|
|
|
if (super.onError(exception)) return true;
|
|
|
|
|
2019-04-17 11:15:40 +00:00
|
|
|
else if (exception instanceof ContentNotAvailableException) {
|
2017-09-03 06:04:18 +00:00
|
|
|
showError(getString(R.string.content_not_available), false);
|
|
|
|
} else {
|
2018-02-16 10:31:25 +00:00
|
|
|
int errorId = exception instanceof YoutubeStreamExtractor.DecryptException
|
|
|
|
? R.string.youtube_signature_decryption_error
|
|
|
|
: exception instanceof ParsingException
|
|
|
|
? R.string.parsing_error
|
|
|
|
: R.string.general_error;
|
|
|
|
onUnrecoverableError(exception,
|
|
|
|
UserAction.REQUESTED_STREAM,
|
|
|
|
NewPipe.getNameOfService(serviceId),
|
|
|
|
url,
|
|
|
|
errorId);
|
2017-06-15 14:26:48 +00:00
|
|
|
}
|
2017-09-03 06:04:18 +00:00
|
|
|
|
|
|
|
return true;
|
2017-06-15 14:26:48 +00:00
|
|
|
}
|
2017-08-12 04:50:25 +00:00
|
|
|
|
2019-04-13 07:31:32 +00:00
|
|
|
private void updateProgressInfo(@NonNull final StreamInfo info) {
|
|
|
|
if (positionSubscriber != null) {
|
|
|
|
positionSubscriber.dispose();
|
|
|
|
}
|
|
|
|
final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(activity);
|
|
|
|
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 21:15:01 +00:00
|
|
|
final boolean showPlaybackPosition = prefs.getBoolean(
|
|
|
|
activity.getString(R.string.enable_playback_state_lists_key), true);
|
2019-04-13 07:31:32 +00:00
|
|
|
if (!playbackResumeEnabled || info.getDuration() <= 0) {
|
2019-12-29 21:15:01 +00:00
|
|
|
if (playQueue == null || playQueue.getStreams().isEmpty()
|
|
|
|
|| playQueue.getItem().getRecoveryPosition() == RECOVERY_UNSET || !showPlaybackPosition) {
|
|
|
|
positionView.setVisibility(View.INVISIBLE);
|
|
|
|
detailPositionView.setVisibility(View.GONE);
|
|
|
|
} 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);
|
|
|
|
}
|
2019-04-13 07:31:32 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
final HistoryRecordManager recordManager = new HistoryRecordManager(requireContext());
|
|
|
|
positionSubscriber = recordManager.loadStreamState(info)
|
|
|
|
.subscribeOn(Schedulers.io())
|
|
|
|
.onErrorComplete()
|
|
|
|
.observeOn(AndroidSchedulers.mainThread())
|
|
|
|
.subscribe(state -> {
|
2019-12-29 21:15:01 +00:00
|
|
|
showPlaybackProgress(state.getProgressTime(), info.getDuration() * 1000);
|
2019-04-13 07:31:32 +00:00
|
|
|
animateView(positionView, true, 500);
|
|
|
|
animateView(detailPositionView, true, 500);
|
|
|
|
}, e -> {
|
|
|
|
if (DEBUG) e.printStackTrace();
|
|
|
|
}, () -> {
|
2019-12-29 21:15:01 +00:00
|
|
|
// OnComplete, do nothing
|
2019-04-13 07:31:32 +00:00
|
|
|
});
|
2017-08-12 04:50:25 +00:00
|
|
|
}
|
2019-12-29 21:15:01 +00:00
|
|
|
|
|
|
|
private void showPlaybackProgress(long progress, long duration) {
|
|
|
|
final int progressSeconds = (int) TimeUnit.MILLISECONDS.toSeconds(progress);
|
|
|
|
final int durationSeconds = (int) TimeUnit.MILLISECONDS.toSeconds(duration);
|
|
|
|
positionView.setMax(durationSeconds);
|
|
|
|
positionView.setProgress(progressSeconds);
|
|
|
|
detailPositionView.setText(Localization.getDurationString(progressSeconds));
|
|
|
|
}
|
|
|
|
|
|
|
|
/*//////////////////////////////////////////////////////////////////////////
|
|
|
|
// Player event listener
|
|
|
|
//////////////////////////////////////////////////////////////////////////*/
|
|
|
|
|
2020-01-06 10:39:01 +00:00
|
|
|
@Override
|
|
|
|
public void onQueueUpdate(PlayQueue queue) {
|
|
|
|
playQueue = queue;
|
|
|
|
// 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
|
|
|
|
if (stack.isEmpty() || !stack.peek().getPlayQueue().equals(queue))
|
|
|
|
stack.push(new StackItem(serviceId, url, name, playQueue));
|
|
|
|
|
|
|
|
if (DEBUG) {
|
|
|
|
Log.d(TAG, "onQueueUpdate() called with: serviceId = ["
|
|
|
|
+ serviceId + "], videoUrl = [" + url + "], name = [" + name + "], playQueue = [" + playQueue + "]");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-12-29 21:15:01 +00:00
|
|
|
@Override
|
|
|
|
public void onPlaybackUpdate(int state, int repeatMode, boolean shuffled, PlaybackParameters parameters) {
|
|
|
|
setOverlayPlayPauseImage();
|
|
|
|
|
|
|
|
switch (state) {
|
|
|
|
case BasePlayer.STATE_COMPLETED:
|
|
|
|
restoreDefaultOrientation();
|
|
|
|
break;
|
|
|
|
case BasePlayer.STATE_PLAYING:
|
|
|
|
if (positionView.getAlpha() != 1f) animateView(positionView, true, 100);
|
|
|
|
if (detailPositionView.getAlpha() != 1f) animateView(detailPositionView, true, 100);
|
|
|
|
setupOrientation();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onProgressUpdate(int currentProgress, int duration, int bufferPercent) {
|
|
|
|
// Progress updates every second even if media is paused. It's useless until playing
|
|
|
|
if (!player.getPlayer().isPlaying() || playQueue == null) return;
|
|
|
|
showPlaybackProgress(currentProgress, duration);
|
|
|
|
|
|
|
|
// We don't want to interrupt playback and don't want to see notification if player is stopped
|
|
|
|
// since next lines of code will enable background playback if needed
|
|
|
|
if (!player.videoPlayerSelected()) return;
|
|
|
|
|
|
|
|
// This will be called when user goes to another app
|
|
|
|
if (isFragmentStopped) {
|
|
|
|
// Video enabled. Let's think what to do with source in background
|
|
|
|
if (player.backgroundPlaybackEnabled())
|
|
|
|
player.useVideoSource(false);
|
|
|
|
else if (player.minimizeOnPopupEnabled())
|
|
|
|
NavigationHelper.playOnPopupPlayer(activity, playQueue, true);
|
2020-01-03 05:05:31 +00:00
|
|
|
else player.onPause();
|
2019-12-29 21:15:01 +00:00
|
|
|
}
|
|
|
|
else player.useVideoSource(true);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onMetadataUpdate(StreamInfo info) {
|
2020-01-06 10:39:01 +00:00
|
|
|
if (!stack.isEmpty()) {
|
|
|
|
// 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
|
|
|
|
StackItem peek = stack.peek();
|
|
|
|
peek.setTitle(info.getName());
|
|
|
|
peek.setUrl(info.getUrl());
|
|
|
|
}
|
|
|
|
|
2019-12-29 21:15:01 +00:00
|
|
|
if (currentInfo == info) return;
|
|
|
|
|
|
|
|
currentInfo = info;
|
|
|
|
setAutoplay(false);
|
|
|
|
prepareAndHandleInfo(info, true);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onPlayerError(ExoPlaybackException error) {
|
|
|
|
if (error.type == ExoPlaybackException.TYPE_SOURCE || error.type == ExoPlaybackException.TYPE_UNEXPECTED) {
|
|
|
|
hideMainPlayer();
|
|
|
|
if (playerService != null && player.isInFullscreen())
|
|
|
|
player.toggleFullscreen();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onServiceStopped() {
|
|
|
|
unbind();
|
|
|
|
setOverlayPlayPauseImage();
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onFullscreenStateChanged(boolean fullscreen) {
|
|
|
|
if (playerService.getView() == null || player.getParentActivity() == null)
|
|
|
|
return;
|
|
|
|
|
|
|
|
View view = playerService.getView();
|
|
|
|
ViewGroup parent = (ViewGroup) view.getParent();
|
|
|
|
if (parent == null) return;
|
|
|
|
|
|
|
|
if (fullscreen) {
|
|
|
|
hideSystemUIIfNeeded();
|
|
|
|
} else {
|
|
|
|
showSystemUi();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (relatedStreamsLayout != null) relatedStreamsLayout.setVisibility(fullscreen ? View.GONE : View.VISIBLE);
|
|
|
|
|
|
|
|
addVideoPlayerView();
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Will scroll down to description view after long click on moreOptionsButton
|
|
|
|
* */
|
|
|
|
@Override
|
|
|
|
public void onMoreOptionsLongClicked() {
|
|
|
|
CoordinatorLayout.LayoutParams params = (CoordinatorLayout.LayoutParams) appBarLayout.getLayoutParams();
|
|
|
|
AppBarLayout.Behavior behavior = (AppBarLayout.Behavior) params.getBehavior();
|
|
|
|
ValueAnimator valueAnimator = ValueAnimator.ofInt(0, -getView().findViewById(R.id.player_placeholder).getHeight());
|
|
|
|
valueAnimator.setInterpolator(new DecelerateInterpolator());
|
|
|
|
valueAnimator.addUpdateListener(animation -> {
|
|
|
|
behavior.setTopAndBottomOffset((int) animation.getAnimatedValue());
|
|
|
|
appBarLayout.requestLayout();
|
|
|
|
});
|
|
|
|
valueAnimator.setInterpolator(new DecelerateInterpolator());
|
|
|
|
valueAnimator.setDuration(500);
|
|
|
|
valueAnimator.start();
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public boolean isFragmentStopped() {
|
|
|
|
return isFragmentStopped;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*//////////////////////////////////////////////////////////////////////////
|
|
|
|
// Player related utils
|
|
|
|
//////////////////////////////////////////////////////////////////////////*/
|
|
|
|
|
|
|
|
private void showSystemUi() {
|
|
|
|
if (DEBUG) Log.d(TAG, "showSystemUi() called");
|
|
|
|
|
|
|
|
getActivity().getWindow().getDecorView().setSystemUiVisibility(0);
|
|
|
|
getActivity().getWindow().clearFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS);
|
|
|
|
}
|
|
|
|
|
|
|
|
private void hideSystemUi() {
|
|
|
|
if (DEBUG) Log.d(TAG, "hideSystemUi() called");
|
|
|
|
|
2020-01-03 05:05:31 +00:00
|
|
|
int visibility = View.SYSTEM_UI_FLAG_LAYOUT_STABLE
|
|
|
|
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
|
|
|
|
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
|
|
|
|
| View.SYSTEM_UI_FLAG_FULLSCREEN
|
|
|
|
| View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
|
|
|
|
| View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
|
|
|
|
activity.getWindow().getDecorView().setSystemUiVisibility(visibility);
|
2019-12-29 21:15:01 +00:00
|
|
|
activity.getWindow().setFlags(
|
|
|
|
WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS, WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Listener implementation
|
|
|
|
public void hideSystemUIIfNeeded() {
|
|
|
|
if (player != null && player.isInFullscreen() && bottomSheetBehavior.getState() == BottomSheetBehavior.STATE_EXPANDED)
|
|
|
|
hideSystemUi();
|
|
|
|
}
|
|
|
|
|
|
|
|
private void setupBrightness(boolean save) {
|
|
|
|
WindowManager.LayoutParams lp = getActivity().getWindow().getAttributes();
|
|
|
|
float brightnessLevel;
|
|
|
|
|
|
|
|
if (save) {
|
|
|
|
// Save current brightness level
|
|
|
|
PlayerHelper.setScreenBrightness(activity, lp.screenBrightness);
|
|
|
|
|
|
|
|
// Restore the old brightness when fragment.onPause() called.
|
|
|
|
// It means when user leaves this fragment brightness will be set to system brightness
|
|
|
|
lp.screenBrightness = -1;
|
|
|
|
} else {
|
|
|
|
// Restore already saved brightness level
|
|
|
|
brightnessLevel = PlayerHelper.getScreenBrightness(activity);
|
|
|
|
if (brightnessLevel <= 0.0f && brightnessLevel > 1.0f)
|
|
|
|
return;
|
|
|
|
|
|
|
|
lp.screenBrightness = brightnessLevel;
|
|
|
|
}
|
|
|
|
getActivity().getWindow().setAttributes(lp);
|
|
|
|
}
|
|
|
|
|
|
|
|
private void checkLandscape() {
|
|
|
|
if ((!player.isPlaying() && player.getPlayQueue() != playQueue) || player.getPlayQueue() == null)
|
|
|
|
setAutoplay(true);
|
|
|
|
|
|
|
|
// Let's give a user time to look at video information page if video is not playing
|
|
|
|
if (player.isPlaying())
|
|
|
|
player.checkLandscape();
|
|
|
|
}
|
|
|
|
|
|
|
|
private boolean isLandscape() {
|
|
|
|
return getResources().getDisplayMetrics().heightPixels < getResources().getDisplayMetrics().widthPixels;
|
|
|
|
}
|
|
|
|
|
2020-01-03 05:05:31 +00:00
|
|
|
private boolean isInMultiWindow() {
|
|
|
|
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && activity.isInMultiWindowMode();
|
|
|
|
}
|
|
|
|
|
2019-12-29 21:15:01 +00:00
|
|
|
/*
|
|
|
|
* Means that the player fragment was swiped away via BottomSheetLayout and is empty but ready for any new actions. See cleanUp()
|
|
|
|
* */
|
|
|
|
private boolean wasCleared() {
|
|
|
|
return url == null;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Remove unneeded information while waiting for a next task
|
|
|
|
* */
|
|
|
|
private void cleanUp() {
|
|
|
|
// New beginning
|
|
|
|
stack.clear();
|
|
|
|
stopService();
|
|
|
|
setInitialData(0,null,"", null);
|
|
|
|
currentInfo = null;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*//////////////////////////////////////////////////////////////////////////
|
|
|
|
// Bottom mini player
|
|
|
|
//////////////////////////////////////////////////////////////////////////*/
|
|
|
|
|
|
|
|
private void setupBottomPlayer() {
|
|
|
|
CoordinatorLayout.LayoutParams params = (CoordinatorLayout.LayoutParams) appBarLayout.getLayoutParams();
|
|
|
|
AppBarLayout.Behavior behavior = (AppBarLayout.Behavior) params.getBehavior();
|
|
|
|
|
|
|
|
FrameLayout bottomSheetLayout = activity.findViewById(R.id.fragment_player_holder);
|
|
|
|
bottomSheetBehavior = BottomSheetBehavior.from(bottomSheetLayout);
|
|
|
|
bottomSheetBehavior.setState(bottomSheetState);
|
|
|
|
final int peekHeight = getResources().getDimensionPixelSize(R.dimen.mini_player_height);
|
|
|
|
if (bottomSheetState != BottomSheetBehavior.STATE_HIDDEN) {
|
|
|
|
bottomSheetBehavior.setPeekHeight(peekHeight);
|
|
|
|
if (bottomSheetState == BottomSheetBehavior.STATE_COLLAPSED)
|
|
|
|
setOverlayLook(appBarLayout, behavior, 1 - MAX_OVERLAY_ALPHA);
|
|
|
|
else if (bottomSheetState == BottomSheetBehavior.STATE_EXPANDED)
|
|
|
|
setOverlayElementsClickable(false);
|
|
|
|
}
|
|
|
|
|
|
|
|
bottomSheetBehavior.setBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() {
|
|
|
|
@Override public void onStateChanged(@NonNull View bottomSheet, int newState) {
|
|
|
|
bottomSheetState = newState;
|
|
|
|
|
|
|
|
switch (newState) {
|
|
|
|
case BottomSheetBehavior.STATE_HIDDEN:
|
|
|
|
bottomSheetBehavior.setPeekHeight(0);
|
|
|
|
cleanUp();
|
|
|
|
break;
|
|
|
|
case BottomSheetBehavior.STATE_EXPANDED:
|
|
|
|
bottomSheetBehavior.setPeekHeight(peekHeight);
|
|
|
|
// Disable click because overlay buttons located on top of buttons from the player
|
|
|
|
setOverlayElementsClickable(false);
|
|
|
|
hideSystemUIIfNeeded();
|
2019-12-31 16:06:39 +00:00
|
|
|
if (isLandscape() && player != null && player.isPlaying() && !player.isInFullscreen())
|
|
|
|
player.toggleFullscreen();
|
2019-12-29 21:15:01 +00:00
|
|
|
break;
|
|
|
|
case BottomSheetBehavior.STATE_COLLAPSED:
|
|
|
|
// Re-enable clicks
|
|
|
|
setOverlayElementsClickable(true);
|
2020-01-06 10:39:01 +00:00
|
|
|
if (player != null && player.isInFullscreen()) showSystemUi();
|
2019-12-29 21:15:01 +00:00
|
|
|
break;
|
|
|
|
case BottomSheetBehavior.STATE_DRAGGING:
|
2020-01-03 16:19:14 +00:00
|
|
|
if (player != null && player.isControlsVisible()) player.hideControls(0, 0);
|
2019-12-29 21:15:01 +00:00
|
|
|
break;
|
|
|
|
case BottomSheetBehavior.STATE_SETTLING:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
@Override public void onSlide(@NonNull View bottomSheet, float slideOffset) {
|
|
|
|
setOverlayLook(appBarLayout, behavior, slideOffset);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
// User opened a new page and the player will hide itself
|
|
|
|
activity.getSupportFragmentManager().addOnBackStackChangedListener(() -> {
|
|
|
|
if (bottomSheetBehavior.getState() == BottomSheetBehavior.STATE_EXPANDED)
|
|
|
|
bottomSheetBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
private void setOverlayPlayPauseImage() {
|
|
|
|
boolean playing = player != null && player.getPlayer().getPlayWhenReady();
|
|
|
|
int attr = playing ? R.attr.pause : R.attr.play;
|
|
|
|
overlayPlayPauseButton.setImageResource(ThemeHelper.resolveResourceIdFromAttr(activity, attr));
|
|
|
|
}
|
|
|
|
|
|
|
|
private void setOverlayLook(AppBarLayout appBarLayout, AppBarLayout.Behavior behavior, float slideOffset) {
|
|
|
|
if (behavior != null) {
|
|
|
|
overlay.setAlpha(Math.min(MAX_OVERLAY_ALPHA, 1 - slideOffset));
|
|
|
|
|
|
|
|
behavior.setTopAndBottomOffset((int)(-appBarLayout.getTotalScrollRange() * (1 - slideOffset) / 3));
|
|
|
|
appBarLayout.requestLayout();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private void setOverlayElementsClickable(boolean enable) {
|
|
|
|
overlayThumbnailImageView.setClickable(enable);
|
|
|
|
overlayThumbnailImageView.setLongClickable(enable);
|
|
|
|
overlayMetadata.setClickable(enable);
|
|
|
|
overlayMetadata.setLongClickable(enable);
|
|
|
|
overlayButtons.setClickable(enable);
|
|
|
|
overlayPlayPauseButton.setClickable(enable);
|
|
|
|
overlayCloseButton.setClickable(enable);
|
|
|
|
}
|
2018-11-20 22:10:50 +00:00
|
|
|
}
|