Use view binding in VideoDetailFragment.

This commit is contained in:
Isira Seneviratne 2021-01-17 09:51:11 +05:30
parent 098c954ef1
commit fe92abde0e
5 changed files with 221 additions and 328 deletions

View File

@ -26,11 +26,7 @@ import android.view.ViewTreeObserver;
import android.view.WindowManager; import android.view.WindowManager;
import android.view.animation.DecelerateInterpolator; import android.view.animation.DecelerateInterpolator;
import android.widget.FrameLayout; import android.widget.FrameLayout;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RelativeLayout; import android.widget.RelativeLayout;
import android.widget.TextView;
import androidx.annotation.DrawableRes; import androidx.annotation.DrawableRes;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
@ -44,13 +40,11 @@ import androidx.core.content.ContextCompat;
import androidx.core.text.HtmlCompat; import androidx.core.text.HtmlCompat;
import androidx.fragment.app.Fragment; import androidx.fragment.app.Fragment;
import androidx.preference.PreferenceManager; import androidx.preference.PreferenceManager;
import androidx.viewpager.widget.ViewPager;
import com.google.android.exoplayer2.ExoPlaybackException; import com.google.android.exoplayer2.ExoPlaybackException;
import com.google.android.exoplayer2.PlaybackParameters; import com.google.android.exoplayer2.PlaybackParameters;
import com.google.android.material.appbar.AppBarLayout; import com.google.android.material.appbar.AppBarLayout;
import com.google.android.material.bottomsheet.BottomSheetBehavior; import com.google.android.material.bottomsheet.BottomSheetBehavior;
import com.google.android.material.tabs.TabLayout;
import com.nostra13.universalimageloader.core.assist.FailReason; import com.nostra13.universalimageloader.core.assist.FailReason;
import com.nostra13.universalimageloader.core.listener.ImageLoadingListener; import com.nostra13.universalimageloader.core.listener.ImageLoadingListener;
import com.nostra13.universalimageloader.core.listener.SimpleImageLoadingListener; import com.nostra13.universalimageloader.core.listener.SimpleImageLoadingListener;
@ -58,6 +52,7 @@ import com.nostra13.universalimageloader.core.listener.SimpleImageLoadingListene
import org.schabi.newpipe.App; import org.schabi.newpipe.App;
import org.schabi.newpipe.R; import org.schabi.newpipe.R;
import org.schabi.newpipe.ReCaptchaActivity; import org.schabi.newpipe.ReCaptchaActivity;
import org.schabi.newpipe.databinding.FragmentVideoDetailBinding;
import org.schabi.newpipe.download.DownloadDialog; import org.schabi.newpipe.download.DownloadDialog;
import org.schabi.newpipe.extractor.InfoItem; import org.schabi.newpipe.extractor.InfoItem;
import org.schabi.newpipe.extractor.NewPipe; import org.schabi.newpipe.extractor.NewPipe;
@ -102,7 +97,6 @@ import org.schabi.newpipe.util.PermissionHelper;
import org.schabi.newpipe.util.ShareUtils; import org.schabi.newpipe.util.ShareUtils;
import org.schabi.newpipe.util.TextLinkifier; import org.schabi.newpipe.util.TextLinkifier;
import org.schabi.newpipe.util.ThemeHelper; import org.schabi.newpipe.util.ThemeHelper;
import org.schabi.newpipe.views.AnimatedProgressBar;
import org.schabi.newpipe.views.LargeTextMovementMethod; import org.schabi.newpipe.views.LargeTextMovementMethod;
import java.util.Iterator; import java.util.Iterator;
@ -120,10 +114,10 @@ import io.reactivex.rxjava3.schedulers.Schedulers;
import static android.text.TextUtils.isEmpty; import static android.text.TextUtils.isEmpty;
import static org.schabi.newpipe.extractor.StreamingService.ServiceInfo.MediaCapability.COMMENTS; import static org.schabi.newpipe.extractor.StreamingService.ServiceInfo.MediaCapability.COMMENTS;
import static org.schabi.newpipe.extractor.stream.StreamExtractor.NO_AGE_LIMIT; import static org.schabi.newpipe.extractor.stream.StreamExtractor.NO_AGE_LIMIT;
import static org.schabi.newpipe.ktx.ViewUtils.animate;
import static org.schabi.newpipe.player.helper.PlayerHelper.globalScreenOrientationLocked; import static org.schabi.newpipe.player.helper.PlayerHelper.globalScreenOrientationLocked;
import static org.schabi.newpipe.player.helper.PlayerHelper.isClearingQueueConfirmationRequired; import static org.schabi.newpipe.player.helper.PlayerHelper.isClearingQueueConfirmationRequired;
import static org.schabi.newpipe.player.playqueue.PlayQueueItem.RECOVERY_UNSET; import static org.schabi.newpipe.player.playqueue.PlayQueueItem.RECOVERY_UNSET;
import static org.schabi.newpipe.ktx.ViewUtils.animate;
import static org.schabi.newpipe.util.ExtractorHelper.showMetaInfoInTextView; import static org.schabi.newpipe.util.ExtractorHelper.showMetaInfoInTextView;
public final class VideoDetailFragment public final class VideoDetailFragment
@ -194,66 +188,14 @@ public final class VideoDetailFragment
// Views // Views
//////////////////////////////////////////////////////////////////////////*/ //////////////////////////////////////////////////////////////////////////*/
private LinearLayout contentRootLayoutHiding; private FragmentVideoDetailBinding binding;
private View thumbnailBackgroundButton;
private ImageView thumbnailImageView;
private ImageView thumbnailPlayButton;
private AnimatedProgressBar positionView;
private ViewGroup playerPlaceholder;
private View videoTitleRoot;
private TextView videoTitleTextView;
private ImageView videoTitleToggleArrow;
private TextView videoCountView;
private TextView detailControlsBackground;
private TextView detailControlsPopup;
private TextView detailControlsAddToPlaylist;
private TextView detailControlsDownload;
private TextView appendControlsDetail;
private TextView detailDurationView;
private TextView detailPositionView;
private View detailMetaInfoSeparator;
private TextView detailMetaInfoTextView;
private LinearLayout videoDescriptionRootLayout;
private TextView videoUploadDateView;
private TextView videoDescriptionView;
private View uploaderRootLayout;
private TextView uploaderTextView;
private ImageView uploaderThumb;
private TextView subChannelTextView;
private ImageView subChannelThumb;
private TextView thumbsUpTextView;
private ImageView thumbsUpImageView;
private TextView thumbsDownTextView;
private ImageView thumbsDownImageView;
private TextView thumbsDisabledTextView;
private RelativeLayout overlay;
private LinearLayout overlayMetadata;
private ImageView overlayThumbnailImageView;
private TextView overlayTitleTextView;
private TextView overlayChannelTextView;
private LinearLayout overlayButtons;
private ImageButton overlayPlayPauseButton;
private ImageButton overlayCloseButton;
private AppBarLayout appBarLayout;
private ViewPager viewPager;
private TabAdapter pageAdapter; private TabAdapter pageAdapter;
private TabLayout tabLayout;
private FrameLayout relatedStreamsLayout;
private ContentObserver settingsContentObserver; private ContentObserver settingsContentObserver;
private MainPlayer playerService; private MainPlayer playerService;
private Player player; private Player player;
/*////////////////////////////////////////////////////////////////////////// /*//////////////////////////////////////////////////////////////////////////
// Service management // Service management
//////////////////////////////////////////////////////////////////////////*/ //////////////////////////////////////////////////////////////////////////*/
@ -373,7 +315,7 @@ public final class VideoDetailFragment
PreferenceManager.getDefaultSharedPreferences(requireContext()) PreferenceManager.getDefaultSharedPreferences(requireContext())
.edit() .edit()
.putString(getString(R.string.stream_info_selected_tab_key), .putString(getString(R.string.stream_info_selected_tab_key),
pageAdapter.getItemTitle(viewPager.getCurrentItem())) pageAdapter.getItemTitle(binding.viewPager.getCurrentItem()))
.apply(); .apply();
} }
@ -416,6 +358,7 @@ public final class VideoDetailFragment
@Override @Override
public void onDestroy() { public void onDestroy() {
super.onDestroy(); super.onDestroy();
binding = null;
// Stop the service when user leaves the app with double back press // Stop the service when user leaves the app with double back press
// if video player is selected. Otherwise unbind // if video player is selected. Otherwise unbind
@ -580,9 +523,7 @@ public final class VideoDetailFragment
break; break;
case R.id.overlay_thumbnail: case R.id.overlay_thumbnail:
case R.id.overlay_metadata_layout: case R.id.overlay_metadata_layout:
if (currentInfo != null) { openChannel(currentInfo.getUploaderUrl(), currentInfo.getUploaderName());
openChannel(currentInfo.getUploaderUrl(), currentInfo.getUploaderName());
}
break; break;
case R.id.detail_uploader_root_layout: case R.id.detail_uploader_root_layout:
if (isEmpty(currentInfo.getSubChannelUrl())) { if (isEmpty(currentInfo.getSubChannelUrl())) {
@ -594,7 +535,7 @@ public final class VideoDetailFragment
break; break;
case R.id.detail_title_root_layout: case R.id.detail_title_root_layout:
ShareUtils.copyToClipboard(requireContext(), ShareUtils.copyToClipboard(requireContext(),
videoTitleTextView.getText().toString()); binding.detailVideoTitleView.getText().toString());
break; break;
} }
@ -602,18 +543,18 @@ public final class VideoDetailFragment
} }
private void toggleTitleAndDescription() { private void toggleTitleAndDescription() {
if (videoDescriptionRootLayout.getVisibility() == View.VISIBLE) { if (binding.detailDescriptionRootLayout.getVisibility() == View.VISIBLE) {
videoTitleTextView.setMaxLines(1); binding.detailVideoTitleView.setMaxLines(1);
videoDescriptionRootLayout.setVisibility(View.GONE); binding.detailDescriptionRootLayout.setVisibility(View.GONE);
videoDescriptionView.setFocusable(false); binding.detailDescriptionView.setFocusable(false);
videoTitleToggleArrow.setImageResource( binding.detailToggleDescriptionView.setImageResource(
ThemeHelper.resolveResourceIdFromAttr(requireContext(), R.attr.ic_expand_more)); ThemeHelper.resolveResourceIdFromAttr(requireContext(), R.attr.ic_expand_more));
} else { } else {
videoTitleTextView.setMaxLines(10); binding.detailVideoTitleView.setMaxLines(10);
videoDescriptionRootLayout.setVisibility(View.VISIBLE); binding.detailDescriptionRootLayout.setVisibility(View.VISIBLE);
videoDescriptionView.setFocusable(true); binding.detailDescriptionView.setFocusable(true);
videoDescriptionView.setMovementMethod(new LargeTextMovementMethod()); binding.detailDescriptionView.setMovementMethod(new LargeTextMovementMethod());
videoTitleToggleArrow.setImageResource( binding.detailToggleDescriptionView.setImageResource(
ThemeHelper.resolveResourceIdFromAttr(requireContext(), R.attr.ic_expand_less)); ThemeHelper.resolveResourceIdFromAttr(requireContext(), R.attr.ic_expand_less));
} }
} }
@ -625,107 +566,55 @@ public final class VideoDetailFragment
@Override @Override
protected void initViews(final View rootView, final Bundle savedInstanceState) { protected void initViews(final View rootView, final Bundle savedInstanceState) {
super.initViews(rootView, savedInstanceState); super.initViews(rootView, savedInstanceState);
thumbnailBackgroundButton = rootView.findViewById(R.id.detail_thumbnail_root_layout); binding = FragmentVideoDetailBinding.bind(rootView);
thumbnailImageView = rootView.findViewById(R.id.detail_thumbnail_image_view);
thumbnailPlayButton = rootView.findViewById(R.id.detail_thumbnail_play_button);
playerPlaceholder = rootView.findViewById(R.id.player_placeholder);
contentRootLayoutHiding = rootView.findViewById(R.id.detail_content_root_hiding);
videoTitleRoot = rootView.findViewById(R.id.detail_title_root_layout);
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);
positionView = rootView.findViewById(R.id.position_view);
detailControlsBackground = rootView.findViewById(R.id.detail_controls_background);
detailControlsPopup = rootView.findViewById(R.id.detail_controls_popup);
detailControlsAddToPlaylist = rootView.findViewById(R.id.detail_controls_playlist_append);
detailControlsDownload = rootView.findViewById(R.id.detail_controls_download);
appendControlsDetail = rootView.findViewById(R.id.touch_append_detail);
detailDurationView = rootView.findViewById(R.id.detail_duration_view);
detailPositionView = rootView.findViewById(R.id.detail_position_view);
detailMetaInfoSeparator = rootView.findViewById(R.id.detail_meta_info_separator);
detailMetaInfoTextView = rootView.findViewById(R.id.detail_meta_info_text_view);
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);
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);
uploaderRootLayout = rootView.findViewById(R.id.detail_uploader_root_layout);
uploaderTextView = rootView.findViewById(R.id.detail_uploader_text_view);
uploaderThumb = rootView.findViewById(R.id.detail_uploader_thumbnail_view);
subChannelTextView = rootView.findViewById(R.id.detail_sub_channel_text_view);
subChannelThumb = rootView.findViewById(R.id.detail_sub_channel_thumbnail_view);
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);
appBarLayout = rootView.findViewById(R.id.appbarlayout);
viewPager = rootView.findViewById(R.id.viewpager);
pageAdapter = new TabAdapter(getChildFragmentManager()); pageAdapter = new TabAdapter(getChildFragmentManager());
viewPager.setAdapter(pageAdapter); binding.viewPager.setAdapter(pageAdapter);
tabLayout = rootView.findViewById(R.id.tablayout); binding.tabLayout.setupWithViewPager(binding.viewPager);
tabLayout.setupWithViewPager(viewPager);
relatedStreamsLayout = rootView.findViewById(R.id.relatedStreamsLayout); binding.detailThumbnailRootLayout.requestFocus();
thumbnailBackgroundButton.requestFocus();
if (DeviceUtils.isTv(getContext())) { if (DeviceUtils.isTv(getContext())) {
// remove ripple effects from detail controls // remove ripple effects from detail controls
final int transparent = getResources().getColor(R.color.transparent_background_color); final int transparent = ContextCompat.getColor(requireContext(),
detailControlsAddToPlaylist.setBackgroundColor(transparent); R.color.transparent_background_color);
detailControlsBackground.setBackgroundColor(transparent); binding.detailControlsPlaylistAppend.setBackgroundColor(transparent);
detailControlsPopup.setBackgroundColor(transparent); binding.detailControlsBackground.setBackgroundColor(transparent);
detailControlsDownload.setBackgroundColor(transparent); binding.detailControlsPopup.setBackgroundColor(transparent);
binding.detailControlsDownload.setBackgroundColor(transparent);
} }
} }
@Override @Override
protected void initListeners() { protected void initListeners() {
super.initListeners(); super.initListeners();
videoTitleRoot.setOnLongClickListener(this); binding.detailTitleRootLayout.setOnLongClickListener(this);
uploaderRootLayout.setOnClickListener(this); binding.detailUploaderRootLayout.setOnClickListener(this);
uploaderRootLayout.setOnLongClickListener(this); binding.detailUploaderRootLayout.setOnLongClickListener(this);
videoTitleRoot.setOnClickListener(this); binding.detailTitleRootLayout.setOnClickListener(this);
thumbnailBackgroundButton.setOnClickListener(this); binding.detailThumbnailRootLayout.setOnClickListener(this);
detailControlsBackground.setOnClickListener(this); binding.detailControlsBackground.setOnClickListener(this);
detailControlsPopup.setOnClickListener(this); binding.detailControlsPopup.setOnClickListener(this);
detailControlsAddToPlaylist.setOnClickListener(this); binding.detailControlsPlaylistAppend.setOnClickListener(this);
detailControlsDownload.setOnClickListener(this); binding.detailControlsDownload.setOnClickListener(this);
detailControlsDownload.setOnLongClickListener(this); binding.detailControlsDownload.setOnLongClickListener(this);
detailControlsBackground.setLongClickable(true); binding.detailControlsBackground.setLongClickable(true);
detailControlsPopup.setLongClickable(true); binding.detailControlsPopup.setLongClickable(true);
detailControlsBackground.setOnLongClickListener(this); binding.detailControlsBackground.setOnLongClickListener(this);
detailControlsPopup.setOnLongClickListener(this); binding.detailControlsPopup.setOnLongClickListener(this);
overlayThumbnailImageView.setOnClickListener(this); binding.overlayThumbnail.setOnClickListener(this);
overlayThumbnailImageView.setOnLongClickListener(this); binding.overlayThumbnail.setOnLongClickListener(this);
overlayMetadata.setOnClickListener(this); binding.overlayMetadataLayout.setOnClickListener(this);
overlayMetadata.setOnLongClickListener(this); binding.overlayMetadataLayout.setOnLongClickListener(this);
overlayButtons.setOnClickListener(this); binding.overlayButtonsLayout.setOnClickListener(this);
overlayCloseButton.setOnClickListener(this); binding.overlayCloseButton.setOnClickListener(this);
overlayPlayPauseButton.setOnClickListener(this); binding.overlayPlayPauseButton.setOnClickListener(this);
detailControlsBackground.setOnTouchListener(getOnControlsTouchListener()); binding.detailControlsBackground.setOnTouchListener(getOnControlsTouchListener());
detailControlsPopup.setOnTouchListener(getOnControlsTouchListener()); binding.detailControlsPopup.setOnTouchListener(getOnControlsTouchListener());
setupBottomPlayer(); setupBottomPlayer();
if (!PlayerHolder.bound) { if (!PlayerHolder.bound) {
@ -743,9 +632,9 @@ public final class VideoDetailFragment
} }
if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) { if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) {
animate(appendControlsDetail, true, 250, AnimationType.ALPHA, animate(binding.touchAppendDetail, true, 250, AnimationType.ALPHA,
0, () -> 0, () ->
animate(appendControlsDetail, false, 1500, animate(binding.touchAppendDetail, false, 1500,
AnimationType.ALPHA, 1000)); AnimationType.ALPHA, 1000));
} }
return false; return false;
@ -753,7 +642,7 @@ public final class VideoDetailFragment
} }
private void initThumbnailViews(@NonNull final StreamInfo info) { private void initThumbnailViews(@NonNull final StreamInfo info) {
thumbnailImageView.setImageResource(R.drawable.dummy_thumbnail_dark); binding.detailThumbnailImageView.setImageResource(R.drawable.dummy_thumbnail_dark);
if (!isEmpty(info.getThumbnailUrl())) { if (!isEmpty(info.getThumbnailUrl())) {
final String infoServiceName = NewPipe.getNameOfService(info.getServiceId()); final String infoServiceName = NewPipe.getNameOfService(info.getServiceId());
@ -766,17 +655,19 @@ public final class VideoDetailFragment
} }
}; };
IMAGE_LOADER.displayImage(info.getThumbnailUrl(), thumbnailImageView, IMAGE_LOADER.displayImage(info.getThumbnailUrl(), binding.detailThumbnailImageView,
ImageDisplayConstants.DISPLAY_THUMBNAIL_OPTIONS, onFailListener); ImageDisplayConstants.DISPLAY_THUMBNAIL_OPTIONS, onFailListener);
} }
if (!isEmpty(info.getSubChannelAvatarUrl())) { if (!isEmpty(info.getSubChannelAvatarUrl())) {
IMAGE_LOADER.displayImage(info.getSubChannelAvatarUrl(), subChannelThumb, IMAGE_LOADER.displayImage(info.getSubChannelAvatarUrl(),
binding.detailSubChannelThumbnailView,
ImageDisplayConstants.DISPLAY_AVATAR_OPTIONS); ImageDisplayConstants.DISPLAY_AVATAR_OPTIONS);
} }
if (!isEmpty(info.getUploaderAvatarUrl())) { if (!isEmpty(info.getUploaderAvatarUrl())) {
IMAGE_LOADER.displayImage(info.getUploaderAvatarUrl(), uploaderThumb, IMAGE_LOADER.displayImage(info.getUploaderAvatarUrl(),
binding.detailUploaderThumbnailView,
ImageDisplayConstants.DISPLAY_AVATAR_OPTIONS); ImageDisplayConstants.DISPLAY_AVATAR_OPTIONS);
} }
} }
@ -896,7 +787,7 @@ public final class VideoDetailFragment
return; return;
} }
// Data can already be drawn, don't spend time twice // Data can already be drawn, don't spend time twice
if (info.getName().equals(videoTitleTextView.getText().toString())) { if (info.getName().equals(binding.detailVideoTitleView.getText().toString())) {
return; return;
} }
prepareAndHandleInfo(info, scrollToTop); prepareAndHandleInfo(info, scrollToTop);
@ -984,7 +875,7 @@ public final class VideoDetailFragment
private void initTabs() { private void initTabs() {
if (pageAdapter.getCount() != 0) { if (pageAdapter.getCount() != 0) {
selectedTabTag = pageAdapter.getItemTitle(viewPager.getCurrentItem()); selectedTabTag = pageAdapter.getItemTitle(binding.viewPager.getCurrentItem());
} }
pageAdapter.clearAllItems(); pageAdapter.clearAllItems();
@ -993,7 +884,7 @@ public final class VideoDetailFragment
CommentsFragment.getInstance(serviceId, url, title), COMMENTS_TAB_TAG); CommentsFragment.getInstance(serviceId, url, title), COMMENTS_TAB_TAG);
} }
if (showRelatedStreams && null == relatedStreamsLayout) { if (showRelatedStreams && binding.relatedStreamsLayout == null) {
//temp empty fragment. will be updated in handleResult //temp empty fragment. will be updated in handleResult
pageAdapter.addFragment(new Fragment(), RELATED_TAB_TAG); pageAdapter.addFragment(new Fragment(), RELATED_TAB_TAG);
} }
@ -1005,13 +896,13 @@ public final class VideoDetailFragment
pageAdapter.notifyDataSetUpdate(); pageAdapter.notifyDataSetUpdate();
if (pageAdapter.getCount() < 2) { if (pageAdapter.getCount() < 2) {
tabLayout.setVisibility(View.GONE); binding.tabLayout.setVisibility(View.GONE);
} else { } else {
final int position = pageAdapter.getItemPositionByTitle(selectedTabTag); final int position = pageAdapter.getItemPositionByTitle(selectedTabTag);
if (position != -1) { if (position != -1) {
viewPager.setCurrentItem(position); binding.viewPager.setCurrentItem(position);
} }
tabLayout.setVisibility(View.VISIBLE); binding.tabLayout.setVisibility(View.VISIBLE);
} }
} }
@ -1027,7 +918,7 @@ public final class VideoDetailFragment
} }
public void scrollToTop() { public void scrollToTop() {
appBarLayout.setExpanded(true, true); binding.appBarLayout.setExpanded(true, true);
} }
/*////////////////////////////////////////////////////////////////////////// /*//////////////////////////////////////////////////////////////////////////
@ -1197,14 +1088,14 @@ public final class VideoDetailFragment
} }
// Check if viewHolder already contains a child // Check if viewHolder already contains a child
if (player.getRootView().getParent() != playerPlaceholder) { if (player.getRootView().getParent() != binding.playerPlaceholder) {
playerService.removeViewFromParent(); playerService.removeViewFromParent();
} }
setHeightThumbnail(); setHeightThumbnail();
// Prevent from re-adding a view multiple times // Prevent from re-adding a view multiple times
if (player.getRootView().getParent() == null) { if (player.getRootView().getParent() == null) {
playerPlaceholder.addView(player.getRootView()); binding.playerPlaceholder.addView(player.getRootView());
} }
} }
@ -1219,8 +1110,8 @@ public final class VideoDetailFragment
return; return;
} }
playerPlaceholder.getLayoutParams().height = FrameLayout.LayoutParams.MATCH_PARENT; binding.playerPlaceholder.getLayoutParams().height = FrameLayout.LayoutParams.MATCH_PARENT;
playerPlaceholder.requestLayout(); binding.playerPlaceholder.requestLayout();
} }
private void prepareDescription(final Description description) { private void prepareDescription(final Description description) {
@ -1232,16 +1123,16 @@ public final class VideoDetailFragment
switch (description.getType()) { switch (description.getType()) {
case Description.HTML: case Description.HTML:
disposables.add(TextLinkifier.createLinksFromHtmlBlock(requireContext(), disposables.add(TextLinkifier.createLinksFromHtmlBlock(requireContext(),
description.getContent(), videoDescriptionView, description.getContent(), binding.detailDescriptionView,
HtmlCompat.FROM_HTML_MODE_LEGACY)); HtmlCompat.FROM_HTML_MODE_LEGACY));
break; break;
case Description.MARKDOWN: case Description.MARKDOWN:
disposables.add(TextLinkifier.createLinksFromMarkdownText(requireContext(), disposables.add(TextLinkifier.createLinksFromMarkdownText(requireContext(),
description.getContent(), videoDescriptionView)); description.getContent(), binding.detailDescriptionView));
break; break;
case Description.PLAIN_TEXT: default: case Description.PLAIN_TEXT: default:
disposables.add(TextLinkifier.createLinksFromPlainText(requireContext(), disposables.add(TextLinkifier.createLinksFromPlainText(requireContext(),
description.getContent(), videoDescriptionView)); description.getContent(), binding.detailDescriptionView));
break; break;
} }
} }
@ -1294,10 +1185,10 @@ public final class VideoDetailFragment
} }
private void setHeightThumbnail(final int newHeight, final DisplayMetrics metrics) { private void setHeightThumbnail(final int newHeight, final DisplayMetrics metrics) {
thumbnailImageView.setLayoutParams( binding.detailThumbnailImageView.setLayoutParams(
new FrameLayout.LayoutParams( new FrameLayout.LayoutParams(
RelativeLayout.LayoutParams.MATCH_PARENT, newHeight)); RelativeLayout.LayoutParams.MATCH_PARENT, newHeight));
thumbnailImageView.setMinimumHeight(newHeight); binding.detailThumbnailImageView.setMinimumHeight(newHeight);
if (player != null) { if (player != null) {
final int maxHeight = (int) (metrics.heightPixels * MAX_PLAYER_HEIGHT); final int maxHeight = (int) (metrics.heightPixels * MAX_PLAYER_HEIGHT);
player.getSurfaceView() player.getSurfaceView()
@ -1306,7 +1197,7 @@ public final class VideoDetailFragment
} }
private void showContent() { private void showContent() {
contentRootLayoutHiding.setVisibility(View.VISIBLE); binding.detailContentRootHiding.setVisibility(View.VISIBLE);
} }
protected void setInitialData(final int newServiceId, protected void setInitialData(final int newServiceId,
@ -1320,14 +1211,14 @@ public final class VideoDetailFragment
} }
private void setErrorImage(final int imageResource) { private void setErrorImage(final int imageResource) {
if (thumbnailImageView == null || activity == null) { if (binding == null || activity == null) {
return; return;
} }
thumbnailImageView.setImageDrawable( binding.detailThumbnailImageView.setImageDrawable(
AppCompatResources.getDrawable(requireContext(), imageResource)); AppCompatResources.getDrawable(requireContext(), imageResource));
animate(thumbnailImageView, false, 0, AnimationType.ALPHA, 0, animate(binding.detailThumbnailImageView, false, 0, AnimationType.ALPHA,
() -> animate(thumbnailImageView, true, 500)); 0, () -> animate(binding.detailThumbnailImageView, true, 500));
} }
@Override @Override
@ -1406,35 +1297,35 @@ public final class VideoDetailFragment
//if data is already cached, transition from VISIBLE -> INVISIBLE -> VISIBLE is not required //if data is already cached, transition from VISIBLE -> INVISIBLE -> VISIBLE is not required
if (!ExtractorHelper.isCached(serviceId, url, InfoItem.InfoType.STREAM)) { if (!ExtractorHelper.isCached(serviceId, url, InfoItem.InfoType.STREAM)) {
contentRootLayoutHiding.setVisibility(View.INVISIBLE); binding.detailContentRootHiding.setVisibility(View.INVISIBLE);
} }
animate(thumbnailPlayButton, false, 50); animate(binding.detailThumbnailPlayButton, false, 50);
animate(detailDurationView, false, 100); animate(binding.detailDurationView, false, 100);
animate(detailPositionView, false, 100); animate(binding.detailPositionView, false, 100);
animate(positionView, false, 50); animate(binding.positionView, false, 50);
videoTitleTextView.setText(title); binding.detailVideoTitleView.setText(title);
videoTitleTextView.setMaxLines(1); binding.detailVideoTitleView.setMaxLines(1);
animate(videoTitleTextView, true, 0); animate(binding.detailVideoTitleView, true, 0);
videoDescriptionRootLayout.setVisibility(View.GONE); binding.detailDescriptionRootLayout.setVisibility(View.GONE);
videoTitleToggleArrow.setVisibility(View.GONE); binding.detailToggleDescriptionView.setVisibility(View.GONE);
videoTitleRoot.setClickable(false); binding.detailTitleRootLayout.setClickable(false);
if (relatedStreamsLayout != null) { if (binding.relatedStreamsLayout != null) {
if (showRelatedStreams) { if (showRelatedStreams) {
relatedStreamsLayout.setVisibility( binding.relatedStreamsLayout.setVisibility(
player != null && player.isFullscreen() ? View.GONE : View.INVISIBLE); player != null && player.isFullscreen() ? View.GONE : View.INVISIBLE);
} else { } else {
relatedStreamsLayout.setVisibility(View.GONE); binding.relatedStreamsLayout.setVisibility(View.GONE);
} }
} }
IMAGE_LOADER.cancelDisplayTask(thumbnailImageView); IMAGE_LOADER.cancelDisplayTask(binding.detailThumbnailImageView);
IMAGE_LOADER.cancelDisplayTask(subChannelThumb); IMAGE_LOADER.cancelDisplayTask(binding.detailSubChannelThumbnailView);
thumbnailImageView.setImageBitmap(null); binding.detailThumbnailImageView.setImageBitmap(null);
subChannelThumb.setImageBitmap(null); binding.detailSubChannelThumbnailView.setImageBitmap(null);
} }
@Override @Override
@ -1445,7 +1336,7 @@ public final class VideoDetailFragment
setInitialData(info.getServiceId(), info.getOriginalUrl(), info.getName(), playQueue); setInitialData(info.getServiceId(), info.getOriginalUrl(), info.getName(), playQueue);
if (showRelatedStreams) { if (showRelatedStreams) {
if (null == relatedStreamsLayout) { //phone if (binding.relatedStreamsLayout == null) { //phone
pageAdapter.updateItem(RELATED_TAB_TAG, pageAdapter.updateItem(RELATED_TAB_TAG,
RelatedVideosFragment.getInstance(info)); RelatedVideosFragment.getInstance(info));
pageAdapter.notifyDataSetUpdate(); pageAdapter.notifyDataSetUpdate();
@ -1454,98 +1345,100 @@ public final class VideoDetailFragment
.replace(R.id.relatedStreamsLayout, .replace(R.id.relatedStreamsLayout,
RelatedVideosFragment.getInstance(info)) RelatedVideosFragment.getInstance(info))
.commitAllowingStateLoss(); .commitAllowingStateLoss();
relatedStreamsLayout.setVisibility( binding.relatedStreamsLayout.setVisibility(
player != null && player.isFullscreen() ? View.GONE : View.VISIBLE); player != null && player.isFullscreen() ? View.GONE : View.VISIBLE);
} }
} }
animate(thumbnailPlayButton, true, 200); animate(binding.detailThumbnailPlayButton, true, 200);
videoTitleTextView.setText(title); binding.detailVideoTitleView.setText(title);
if (!isEmpty(info.getSubChannelName())) { if (!isEmpty(info.getSubChannelName())) {
displayBothUploaderAndSubChannel(info); displayBothUploaderAndSubChannel(info);
} else if (!isEmpty(info.getUploaderName())) { } else if (!isEmpty(info.getUploaderName())) {
displayUploaderAsSubChannel(info); displayUploaderAsSubChannel(info);
} else { } else {
uploaderTextView.setVisibility(View.GONE); binding.detailUploadDateView.setVisibility(View.GONE);
uploaderThumb.setVisibility(View.GONE); binding.detailUploaderThumbnailView.setVisibility(View.GONE);
} }
final Drawable buddyDrawable = AppCompatResources.getDrawable(activity, R.drawable.buddy); final Drawable buddyDrawable = AppCompatResources.getDrawable(activity, R.drawable.buddy);
subChannelThumb.setImageDrawable(buddyDrawable); binding.detailSubChannelThumbnailView.setImageDrawable(buddyDrawable);
uploaderThumb.setImageDrawable(buddyDrawable); binding.detailUploaderThumbnailView.setImageDrawable(buddyDrawable);
if (info.getViewCount() >= 0) { if (info.getViewCount() >= 0) {
if (info.getStreamType().equals(StreamType.AUDIO_LIVE_STREAM)) { if (info.getStreamType().equals(StreamType.AUDIO_LIVE_STREAM)) {
videoCountView.setText(Localization.listeningCount(activity, info.getViewCount())); binding.detailViewCountView.setText(Localization.listeningCount(activity,
info.getViewCount()));
} else if (info.getStreamType().equals(StreamType.LIVE_STREAM)) { } else if (info.getStreamType().equals(StreamType.LIVE_STREAM)) {
videoCountView.setText(Localization binding.detailViewCountView.setText(Localization
.localizeWatchingCount(activity, info.getViewCount())); .localizeWatchingCount(activity, info.getViewCount()));
} else { } else {
videoCountView.setText(Localization binding.detailViewCountView.setText(Localization
.localizeViewCount(activity, info.getViewCount())); .localizeViewCount(activity, info.getViewCount()));
} }
videoCountView.setVisibility(View.VISIBLE); binding.detailViewCountView.setVisibility(View.VISIBLE);
} else { } else {
videoCountView.setVisibility(View.GONE); binding.detailViewCountView.setVisibility(View.GONE);
} }
if (info.getDislikeCount() == -1 && info.getLikeCount() == -1) { if (info.getDislikeCount() == -1 && info.getLikeCount() == -1) {
thumbsDownImageView.setVisibility(View.VISIBLE); binding.detailThumbsDownImgView.setVisibility(View.VISIBLE);
thumbsUpImageView.setVisibility(View.VISIBLE); binding.detailThumbsUpImgView.setVisibility(View.VISIBLE);
thumbsUpTextView.setVisibility(View.GONE); binding.detailThumbsUpCountView.setVisibility(View.GONE);
thumbsDownTextView.setVisibility(View.GONE); binding.detailThumbsDownCountView.setVisibility(View.GONE);
thumbsDisabledTextView.setVisibility(View.VISIBLE); binding.detailThumbsDisabledView.setVisibility(View.VISIBLE);
} else { } else {
if (info.getDislikeCount() >= 0) { if (info.getDislikeCount() >= 0) {
thumbsDownTextView.setText(Localization binding.detailThumbsDownCountView.setText(Localization
.shortCount(activity, info.getDislikeCount())); .shortCount(activity, info.getDislikeCount()));
thumbsDownTextView.setVisibility(View.VISIBLE); binding.detailThumbsDownCountView.setVisibility(View.VISIBLE);
thumbsDownImageView.setVisibility(View.VISIBLE); binding.detailThumbsDownImgView.setVisibility(View.VISIBLE);
} else { } else {
thumbsDownTextView.setVisibility(View.GONE); binding.detailThumbsDownCountView.setVisibility(View.GONE);
thumbsDownImageView.setVisibility(View.GONE); binding.detailThumbsDownImgView.setVisibility(View.GONE);
} }
if (info.getLikeCount() >= 0) { if (info.getLikeCount() >= 0) {
thumbsUpTextView.setText(Localization.shortCount(activity, info.getLikeCount())); binding.detailThumbsUpCountView.setText(Localization.shortCount(activity,
thumbsUpTextView.setVisibility(View.VISIBLE); info.getLikeCount()));
thumbsUpImageView.setVisibility(View.VISIBLE); binding.detailThumbsUpCountView.setVisibility(View.VISIBLE);
binding.detailThumbsUpImgView.setVisibility(View.VISIBLE);
} else { } else {
thumbsUpTextView.setVisibility(View.GONE); binding.detailThumbsUpCountView.setVisibility(View.GONE);
thumbsUpImageView.setVisibility(View.GONE); binding.detailThumbsUpImgView.setVisibility(View.GONE);
} }
thumbsDisabledTextView.setVisibility(View.GONE); binding.detailThumbsDisabledView.setVisibility(View.GONE);
} }
if (info.getDuration() > 0) { if (info.getDuration() > 0) {
detailDurationView.setText(Localization.getDurationString(info.getDuration())); binding.detailDurationView.setText(Localization.getDurationString(info.getDuration()));
detailDurationView.setBackgroundColor( binding.detailDurationView.setBackgroundColor(
ContextCompat.getColor(activity, R.color.duration_background_color)); ContextCompat.getColor(activity, R.color.duration_background_color));
animate(detailDurationView, true, 100); animate(binding.detailDurationView, true, 100);
} else if (info.getStreamType() == StreamType.LIVE_STREAM) { } else if (info.getStreamType() == StreamType.LIVE_STREAM) {
detailDurationView.setText(R.string.duration_live); binding.detailDurationView.setText(R.string.duration_live);
detailDurationView.setBackgroundColor( binding.detailDurationView.setBackgroundColor(
ContextCompat.getColor(activity, R.color.live_duration_background_color)); ContextCompat.getColor(activity, R.color.live_duration_background_color));
animate(detailDurationView, true, 100); animate(binding.detailDurationView, true, 100);
} else { } else {
detailDurationView.setVisibility(View.GONE); binding.detailDurationView.setVisibility(View.GONE);
} }
videoDescriptionView.setVisibility(View.GONE); binding.detailDescriptionView.setVisibility(View.GONE);
videoTitleRoot.setClickable(true); binding.detailTitleRootLayout.setClickable(true);
videoTitleToggleArrow.setImageResource( binding.detailToggleDescriptionView.setImageResource(
ThemeHelper.resolveResourceIdFromAttr(requireContext(), R.attr.ic_expand_more)); ThemeHelper.resolveResourceIdFromAttr(requireContext(), R.attr.ic_expand_more));
videoTitleToggleArrow.setVisibility(View.VISIBLE); binding.detailToggleDescriptionView.setVisibility(View.VISIBLE);
videoDescriptionRootLayout.setVisibility(View.GONE); binding.detailDescriptionRootLayout.setVisibility(View.GONE);
if (info.getUploadDate() != null) { if (info.getUploadDate() != null) {
videoUploadDateView.setText(Localization binding.detailUploadDateView.setText(Localization
.localizeUploadDate(activity, info.getUploadDate().offsetDateTime())); .localizeUploadDate(activity, info.getUploadDate().offsetDateTime()));
videoUploadDateView.setVisibility(View.VISIBLE); binding.detailUploadDateView.setVisibility(View.VISIBLE);
} else { } else {
videoUploadDateView.setText(null); binding.detailUploadDateView.setText(null);
videoUploadDateView.setVisibility(View.GONE); binding.detailUploadDateView.setVisibility(View.GONE);
} }
sortedVideoStreams = ListHelper.getSortedStreamVideosList( sortedVideoStreams = ListHelper.getSortedStreamVideosList(
@ -1558,8 +1451,8 @@ public final class VideoDetailFragment
prepareDescription(info.getDescription()); prepareDescription(info.getDescription());
updateProgressInfo(info); updateProgressInfo(info);
initThumbnailViews(info); initThumbnailViews(info);
disposables.add(showMetaInfoInTextView(info.getMetaInfo(), detailMetaInfoTextView, disposables.add(showMetaInfoInTextView(info.getMetaInfo(), binding.detailMetaInfoTextView,
detailMetaInfoSeparator)); binding.detailMetaInfoSeparator));
if (player == null || player.isStopped()) { if (player == null || player.isStopped()) {
updateOverlayData(info.getName(), info.getUploaderName(), info.getThumbnailUrl()); updateOverlayData(info.getName(), info.getUploaderName(), info.getThumbnailUrl());
@ -1573,15 +1466,15 @@ public final class VideoDetailFragment
0); 0);
} }
detailControlsDownload.setVisibility(info.getStreamType() == StreamType.LIVE_STREAM binding.detailControlsDownload.setVisibility(info.getStreamType() == StreamType.LIVE_STREAM
|| info.getStreamType() == StreamType.AUDIO_LIVE_STREAM ? View.GONE : View.VISIBLE); || info.getStreamType() == StreamType.AUDIO_LIVE_STREAM ? View.GONE : View.VISIBLE);
detailControlsBackground.setVisibility(info.getAudioStreams().isEmpty() binding.detailControlsBackground.setVisibility(info.getAudioStreams().isEmpty()
? View.GONE : View.VISIBLE); ? View.GONE : View.VISIBLE);
final boolean noVideoStreams = final boolean noVideoStreams =
info.getVideoStreams().isEmpty() && info.getVideoOnlyStreams().isEmpty(); info.getVideoStreams().isEmpty() && info.getVideoOnlyStreams().isEmpty();
detailControlsPopup.setVisibility(noVideoStreams ? View.GONE : View.VISIBLE); binding.detailControlsPopup.setVisibility(noVideoStreams ? View.GONE : View.VISIBLE);
thumbnailPlayButton.setImageResource( binding.detailThumbnailPlayButton.setImageResource(
noVideoStreams ? R.drawable.ic_headset_shadow : R.drawable.ic_play_arrow_shadow); noVideoStreams ? R.drawable.ic_headset_shadow : R.drawable.ic_play_arrow_shadow);
} }
@ -1589,39 +1482,38 @@ public final class VideoDetailFragment
showError(getString(R.string.restricted_video, showError(getString(R.string.restricted_video,
getString(R.string.show_age_restricted_content_title)), false); getString(R.string.show_age_restricted_content_title)), false);
if (relatedStreamsLayout != null) { // tablet if (binding.relatedStreamsLayout != null) { // tablet
relatedStreamsLayout.setVisibility(View.INVISIBLE); binding.relatedStreamsLayout.setVisibility(View.INVISIBLE);
} }
viewPager.setVisibility(View.GONE); binding.viewPager.setVisibility(View.GONE);
tabLayout.setVisibility(View.GONE); binding.tabLayout.setVisibility(View.GONE);
} }
private void displayUploaderAsSubChannel(final StreamInfo info) { private void displayUploaderAsSubChannel(final StreamInfo info) {
subChannelTextView.setText(info.getUploaderName()); binding.detailSubChannelTextView.setText(info.getUploaderName());
subChannelTextView.setVisibility(View.VISIBLE); binding.detailSubChannelTextView.setVisibility(View.VISIBLE);
subChannelTextView.setSelected(true); binding.detailSubChannelTextView.setSelected(true);
uploaderTextView.setVisibility(View.GONE); binding.detailUploadDateView.setVisibility(View.GONE);
} }
private void displayBothUploaderAndSubChannel(final StreamInfo info) { private void displayBothUploaderAndSubChannel(final StreamInfo info) {
subChannelTextView.setText(info.getSubChannelName()); binding.detailSubChannelTextView.setText(info.getSubChannelName());
subChannelTextView.setVisibility(View.VISIBLE); binding.detailSubChannelTextView.setVisibility(View.VISIBLE);
subChannelTextView.setSelected(true); binding.detailSubChannelTextView.setSelected(true);
subChannelThumb.setVisibility(View.VISIBLE); binding.detailSubChannelThumbnailView.setVisibility(View.VISIBLE);
if (!isEmpty(info.getUploaderName())) { if (!isEmpty(info.getUploaderName())) {
uploaderTextView.setText( binding.detailUploadDateView.setText(
String.format(getString(R.string.video_detail_by), info.getUploaderName())); String.format(getString(R.string.video_detail_by), info.getUploaderName()));
uploaderTextView.setVisibility(View.VISIBLE); binding.detailUploadDateView.setVisibility(View.VISIBLE);
uploaderTextView.setSelected(true); binding.detailUploadDateView.setSelected(true);
} else { } else {
uploaderTextView.setVisibility(View.GONE); binding.detailUploadDateView.setVisibility(View.GONE);
} }
} }
public void openDownloadDialog() { public void openDownloadDialog() {
try { try {
final DownloadDialog downloadDialog = DownloadDialog.newInstance(currentInfo); final DownloadDialog downloadDialog = DownloadDialog.newInstance(currentInfo);
@ -1683,8 +1575,8 @@ public final class VideoDetailFragment
if (playQueue == null || playQueue.getStreams().isEmpty() if (playQueue == null || playQueue.getStreams().isEmpty()
|| playQueue.getItem().getRecoveryPosition() == RECOVERY_UNSET || playQueue.getItem().getRecoveryPosition() == RECOVERY_UNSET
|| !showPlaybackPosition) { || !showPlaybackPosition) {
positionView.setVisibility(View.INVISIBLE); binding.positionView.setVisibility(View.INVISIBLE);
detailPositionView.setVisibility(View.GONE); binding.detailPositionView.setVisibility(View.GONE);
// TODO: Remove this check when separation of concerns is done. // TODO: Remove this check when separation of concerns is done.
// (live streams weren't getting updated because they are mixed) // (live streams weren't getting updated because they are mixed)
if (!info.getStreamType().equals(StreamType.LIVE_STREAM) if (!info.getStreamType().equals(StreamType.LIVE_STREAM)
@ -1695,8 +1587,8 @@ public final class VideoDetailFragment
// Show saved position from backStack if user allows it // Show saved position from backStack if user allows it
showPlaybackProgress(playQueue.getItem().getRecoveryPosition(), showPlaybackProgress(playQueue.getItem().getRecoveryPosition(),
playQueue.getItem().getDuration() * 1000); playQueue.getItem().getDuration() * 1000);
animate(positionView, true, 500); animate(binding.positionView, true, 500);
animate(detailPositionView, true, 500); animate(binding.detailPositionView, true, 500);
} }
return; return;
} }
@ -1710,15 +1602,15 @@ public final class VideoDetailFragment
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
.subscribe(state -> { .subscribe(state -> {
showPlaybackProgress(state.getProgressTime(), info.getDuration() * 1000); showPlaybackProgress(state.getProgressTime(), info.getDuration() * 1000);
animate(positionView, true, 500); animate(binding.positionView, true, 500);
animate(detailPositionView, true, 500); animate(binding.detailPositionView, true, 500);
}, e -> { }, e -> {
if (DEBUG) { if (DEBUG) {
e.printStackTrace(); e.printStackTrace();
} }
}, () -> { }, () -> {
positionView.setVisibility(View.GONE); binding.positionView.setVisibility(View.GONE);
detailPositionView.setVisibility(View.GONE); binding.detailPositionView.setVisibility(View.GONE);
}); });
} }
@ -1727,20 +1619,21 @@ public final class VideoDetailFragment
final int durationSeconds = (int) TimeUnit.MILLISECONDS.toSeconds(duration); final int durationSeconds = (int) TimeUnit.MILLISECONDS.toSeconds(duration);
// If the old and the new progress values have a big difference then use // If the old and the new progress values have a big difference then use
// animation. Otherwise don't because it affects CPU // animation. Otherwise don't because it affects CPU
final boolean shouldAnimate = Math.abs(positionView.getProgress() - progressSeconds) > 2; final boolean shouldAnimate = Math.abs(binding.positionView.getProgress()
positionView.setMax(durationSeconds); - progressSeconds) > 2;
binding.positionView.setMax(durationSeconds);
if (shouldAnimate) { if (shouldAnimate) {
positionView.setProgressAnimated(progressSeconds); binding.positionView.setProgressAnimated(progressSeconds);
} else { } else {
positionView.setProgress(progressSeconds); binding.positionView.setProgress(progressSeconds);
} }
final String position = Localization.getDurationString(progressSeconds); final String position = Localization.getDurationString(progressSeconds);
if (position != detailPositionView.getText()) { if (position != binding.detailPositionView.getText()) {
detailPositionView.setText(position); binding.detailPositionView.setText(position);
} }
if (positionView.getVisibility() != View.VISIBLE) { if (binding.positionView.getVisibility() != View.VISIBLE) {
animate(positionView, true, 100); animate(binding.positionView, true, 100);
animate(detailPositionView, true, 100); animate(binding.detailPositionView, true, 100);
} }
} }
@ -1790,12 +1683,12 @@ public final class VideoDetailFragment
switch (state) { switch (state) {
case Player.STATE_PLAYING: case Player.STATE_PLAYING:
if (positionView.getAlpha() != 1.0f if (binding.positionView.getAlpha() != 1.0f
&& player.getPlayQueue() != null && player.getPlayQueue() != null
&& player.getPlayQueue().getItem() != null && player.getPlayQueue().getItem() != null
&& player.getPlayQueue().getItem().getUrl().equals(url)) { && player.getPlayQueue().getItem().getUrl().equals(url)) {
animate(positionView, true, 100); animate(binding.positionView, true, 100);
animate(detailPositionView, true, 100); animate(binding.detailPositionView, true, 100);
} }
break; break;
} }
@ -1887,8 +1780,8 @@ public final class VideoDetailFragment
showSystemUi(); showSystemUi();
} }
if (relatedStreamsLayout != null) { if (binding.relatedStreamsLayout != null) {
relatedStreamsLayout.setVisibility(fullscreen ? View.GONE : View.VISIBLE); binding.relatedStreamsLayout.setVisibility(fullscreen ? View.GONE : View.VISIBLE);
} }
scrollToTop(); scrollToTop();
@ -1926,14 +1819,14 @@ public final class VideoDetailFragment
@Override @Override
public void onMoreOptionsLongClicked() { public void onMoreOptionsLongClicked() {
final CoordinatorLayout.LayoutParams params = final CoordinatorLayout.LayoutParams params =
(CoordinatorLayout.LayoutParams) appBarLayout.getLayoutParams(); (CoordinatorLayout.LayoutParams) binding.appBarLayout.getLayoutParams();
final AppBarLayout.Behavior behavior = (AppBarLayout.Behavior) params.getBehavior(); final AppBarLayout.Behavior behavior = (AppBarLayout.Behavior) params.getBehavior();
final ValueAnimator valueAnimator = ValueAnimator final ValueAnimator valueAnimator = ValueAnimator
.ofInt(0, -playerPlaceholder.getHeight()); .ofInt(0, -binding.playerPlaceholder.getHeight());
valueAnimator.setInterpolator(new DecelerateInterpolator()); valueAnimator.setInterpolator(new DecelerateInterpolator());
valueAnimator.addUpdateListener(animation -> { valueAnimator.addUpdateListener(animation -> {
behavior.setTopAndBottomOffset((int) animation.getAnimatedValue()); behavior.setTopAndBottomOffset((int) animation.getAnimatedValue());
appBarLayout.requestLayout(); binding.appBarLayout.requestLayout();
}); });
valueAnimator.setInterpolator(new DecelerateInterpolator()); valueAnimator.setInterpolator(new DecelerateInterpolator());
valueAnimator.setDuration(500); valueAnimator.setDuration(500);
@ -2185,7 +2078,7 @@ public final class VideoDetailFragment
mainFragment.setDescendantFocusability(blockDescendants); mainFragment.setDescendantFocusability(blockDescendants);
toolbar.setDescendantFocusability(blockDescendants); toolbar.setDescendantFocusability(blockDescendants);
((ViewGroup) requireView()).setDescendantFocusability(afterDescendants); ((ViewGroup) requireView()).setDescendantFocusability(afterDescendants);
thumbnailBackgroundButton.requestFocus(); binding.detailThumbnailRootLayout.requestFocus();
} }
} }
@ -2215,7 +2108,7 @@ public final class VideoDetailFragment
private void setupBottomPlayer() { private void setupBottomPlayer() {
final CoordinatorLayout.LayoutParams params = final CoordinatorLayout.LayoutParams params =
(CoordinatorLayout.LayoutParams) appBarLayout.getLayoutParams(); (CoordinatorLayout.LayoutParams) binding.appBarLayout.getLayoutParams();
final AppBarLayout.Behavior behavior = (AppBarLayout.Behavior) params.getBehavior(); final AppBarLayout.Behavior behavior = (AppBarLayout.Behavior) params.getBehavior();
final FrameLayout bottomSheetLayout = activity.findViewById(R.id.fragment_player_holder); final FrameLayout bottomSheetLayout = activity.findViewById(R.id.fragment_player_holder);
@ -2226,9 +2119,9 @@ public final class VideoDetailFragment
manageSpaceAtTheBottom(false); manageSpaceAtTheBottom(false);
bottomSheetBehavior.setPeekHeight(peekHeight); bottomSheetBehavior.setPeekHeight(peekHeight);
if (bottomSheetState == BottomSheetBehavior.STATE_COLLAPSED) { if (bottomSheetState == BottomSheetBehavior.STATE_COLLAPSED) {
overlay.setAlpha(MAX_OVERLAY_ALPHA); binding.overlayLayout.setAlpha(MAX_OVERLAY_ALPHA);
} else if (bottomSheetState == BottomSheetBehavior.STATE_EXPANDED) { } else if (bottomSheetState == BottomSheetBehavior.STATE_EXPANDED) {
overlay.setAlpha(0); binding.overlayLayout.setAlpha(0);
setOverlayElementsClickable(false); setOverlayElementsClickable(false);
} }
} }
@ -2264,7 +2157,7 @@ public final class VideoDetailFragment
&& player.videoPlayerSelected()) { && player.videoPlayerSelected()) {
player.toggleFullscreen(); player.toggleFullscreen();
} }
setOverlayLook(appBarLayout, behavior, 1); setOverlayLook(binding.appBarLayout, behavior, 1);
break; break;
case BottomSheetBehavior.STATE_COLLAPSED: case BottomSheetBehavior.STATE_COLLAPSED:
moveFocusToMainFragment(true); moveFocusToMainFragment(true);
@ -2277,7 +2170,7 @@ public final class VideoDetailFragment
if (player != null) { if (player != null) {
player.closeItemsList(); player.closeItemsList();
} }
setOverlayLook(appBarLayout, behavior, 0); setOverlayLook(binding.appBarLayout, behavior, 0);
break; break;
case BottomSheetBehavior.STATE_DRAGGING: case BottomSheetBehavior.STATE_DRAGGING:
case BottomSheetBehavior.STATE_SETTLING: case BottomSheetBehavior.STATE_SETTLING:
@ -2293,7 +2186,7 @@ public final class VideoDetailFragment
@Override @Override
public void onSlide(@NonNull final View bottomSheet, final float slideOffset) { public void onSlide(@NonNull final View bottomSheet, final float slideOffset) {
setOverlayLook(appBarLayout, behavior, slideOffset); setOverlayLook(binding.appBarLayout, behavior, slideOffset);
} }
}); });
@ -2308,11 +2201,11 @@ public final class VideoDetailFragment
private void updateOverlayData(@Nullable final String overlayTitle, private void updateOverlayData(@Nullable final String overlayTitle,
@Nullable final String uploader, @Nullable final String uploader,
@Nullable final String thumbnailUrl) { @Nullable final String thumbnailUrl) {
overlayTitleTextView.setText(isEmpty(title) ? "" : title); binding.overlayTitleTextView.setText(isEmpty(title) ? "" : title);
overlayChannelTextView.setText(isEmpty(uploader) ? "" : uploader); binding.overlayChannelTextView.setText(isEmpty(uploader) ? "" : uploader);
overlayThumbnailImageView.setImageResource(R.drawable.dummy_thumbnail_dark); binding.overlayThumbnail.setImageResource(R.drawable.dummy_thumbnail_dark);
if (!isEmpty(thumbnailUrl)) { if (!isEmpty(thumbnailUrl)) {
IMAGE_LOADER.displayImage(thumbnailUrl, overlayThumbnailImageView, IMAGE_LOADER.displayImage(thumbnailUrl, binding.overlayThumbnail,
ImageDisplayConstants.DISPLAY_THUMBNAIL_OPTIONS, null); ImageDisplayConstants.DISPLAY_THUMBNAIL_OPTIONS, null);
} }
} }
@ -2321,7 +2214,7 @@ public final class VideoDetailFragment
final int attr = playerIsPlaying final int attr = playerIsPlaying
? R.attr.ic_pause ? R.attr.ic_pause
: R.attr.ic_play_arrow; : R.attr.ic_play_arrow;
overlayPlayPauseButton.setImageResource( binding.overlayPlayPauseButton.setImageResource(
ThemeHelper.resolveResourceIdFromAttr(activity, attr)); ThemeHelper.resolveResourceIdFromAttr(activity, attr));
} }
@ -2333,20 +2226,20 @@ public final class VideoDetailFragment
if (behavior == null || slideOffset < 0) { if (behavior == null || slideOffset < 0) {
return; return;
} }
overlay.setAlpha(Math.min(MAX_OVERLAY_ALPHA, 1 - slideOffset)); binding.overlayLayout.setAlpha(Math.min(MAX_OVERLAY_ALPHA, 1 - slideOffset));
// These numbers are not special. They just do a cool transition // These numbers are not special. They just do a cool transition
behavior.setTopAndBottomOffset( behavior.setTopAndBottomOffset(
(int) (-thumbnailImageView.getHeight() * 2 * (1 - slideOffset) / 3)); (int) (-binding.detailThumbnailImageView.getHeight() * 2 * (1 - slideOffset) / 3));
appBar.requestLayout(); appBar.requestLayout();
} }
private void setOverlayElementsClickable(final boolean enable) { private void setOverlayElementsClickable(final boolean enable) {
overlayThumbnailImageView.setClickable(enable); binding.overlayThumbnail.setClickable(enable);
overlayThumbnailImageView.setLongClickable(enable); binding.overlayThumbnail.setLongClickable(enable);
overlayMetadata.setClickable(enable); binding.overlayMetadataLayout.setClickable(enable);
overlayMetadata.setLongClickable(enable); binding.overlayMetadataLayout.setLongClickable(enable);
overlayButtons.setClickable(enable); binding.overlayButtonsLayout.setClickable(enable);
overlayPlayPauseButton.setClickable(enable); binding.overlayPlayPauseButton.setClickable(enable);
overlayCloseButton.setClickable(enable); binding.overlayCloseButton.setClickable(enable);
} }
} }

View File

@ -46,6 +46,6 @@ data class PickerSubscriptionItem(
fun updateSelected(containerView: View, isSelected: Boolean) { fun updateSelected(containerView: View, isSelected: Boolean) {
this.isSelected = isSelected this.isSelected = isSelected
PickerSubscriptionItemBinding.bind(containerView).selectedHighlight PickerSubscriptionItemBinding.bind(containerView).selectedHighlight
.animate(isSelected, 150, AnimationType.LIGHT_SCALE_AND_ALPHA) .animate(isSelected, 150, AnimationType.LIGHT_SCALE_AND_ALPHA)
} }
} }

View File

@ -27,7 +27,7 @@ public class CustomBottomSheetBehavior extends BottomSheetBehavior<FrameLayout>
private boolean skippingInterception = false; private boolean skippingInterception = false;
private final List<Integer> skipInterceptionOfElements = Arrays.asList( private final List<Integer> skipInterceptionOfElements = Arrays.asList(
R.id.detail_content_root_layout, R.id.relatedStreamsLayout, R.id.detail_content_root_layout, R.id.relatedStreamsLayout,
R.id.itemsListPanel, R.id.viewpager, R.id.bottomControls, R.id.itemsListPanel, R.id.view_pager, R.id.bottomControls,
R.id.playPauseButton, R.id.playPreviousButton, R.id.playNextButton); R.id.playPauseButton, R.id.playPreviousButton, R.id.playNextButton);
@Override @Override

View File

@ -23,7 +23,7 @@
android:isScrollContainer="true"> android:isScrollContainer="true">
<com.google.android.material.appbar.AppBarLayout <com.google.android.material.appbar.AppBarLayout
android:id="@+id/appbarlayout" android:id="@+id/app_bar_layout"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:background="@android:color/transparent" android:background="@android:color/transparent"
@ -583,13 +583,13 @@
</com.google.android.material.appbar.AppBarLayout> </com.google.android.material.appbar.AppBarLayout>
<androidx.viewpager.widget.ViewPager <androidx.viewpager.widget.ViewPager
android:id="@+id/viewpager" android:id="@+id/view_pager"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior"> app:layout_behavior="@string/appbar_scrolling_view_behavior">
<com.google.android.material.tabs.TabLayout <com.google.android.material.tabs.TabLayout
android:id="@+id/tablayout" android:id="@+id/tab_layout"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="30dp" android:layout_height="30dp"
android:layout_gravity="bottom|center" android:layout_gravity="bottom|center"

View File

@ -14,7 +14,7 @@
android:layout_height="wrap_content"> android:layout_height="wrap_content">
<com.google.android.material.appbar.AppBarLayout <com.google.android.material.appbar.AppBarLayout
android:id="@+id/appbarlayout" android:id="@+id/app_bar_layout"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:background="@android:color/transparent" android:background="@android:color/transparent"
@ -564,13 +564,13 @@
</com.google.android.material.appbar.AppBarLayout> </com.google.android.material.appbar.AppBarLayout>
<androidx.viewpager.widget.ViewPager <androidx.viewpager.widget.ViewPager
android:id="@+id/viewpager" android:id="@+id/view_pager"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior"> app:layout_behavior="@string/appbar_scrolling_view_behavior">
<com.google.android.material.tabs.TabLayout <com.google.android.material.tabs.TabLayout
android:id="@+id/tablayout" android:id="@+id/tab_layout"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="30dp" android:layout_height="30dp"
android:layout_gravity="bottom|center" android:layout_gravity="bottom|center"