From 5744a1a6873b1b33558183bc01b46da43159d554 Mon Sep 17 00:00:00 2001 From: Ammar Githam Date: Sun, 9 May 2021 02:14:36 +0900 Subject: [PATCH] Add fullscreen mode to post view --- .../adapters/SliderCallbackAdapter.java | 16 +- .../adapters/SliderItemsAdapter.java | 22 +- .../viewholder/SliderPhotoViewHolder.java | 77 +--- .../viewholder/SliderVideoViewHolder.java | 117 ++---- .../viewholder/feed/FeedSliderViewHolder.java | 4 +- .../VideoPlayerCallbackAdapter.java | 10 + .../customviews/VideoPlayerViewHelper.java | 385 ++++++------------ .../fragments/PostViewV2Fragment.java | 306 ++++++++------ .../java/awais/instagrabber/utils/Utils.java | 45 ++ app/src/main/res/layout/dialog_post_view.xml | 1 + .../res/layout/layout_post_view_bottom.xml | 5 + 11 files changed, 434 insertions(+), 554 deletions(-) diff --git a/app/src/main/java/awais/instagrabber/adapters/SliderCallbackAdapter.java b/app/src/main/java/awais/instagrabber/adapters/SliderCallbackAdapter.java index 1cfec468..a92192eb 100644 --- a/app/src/main/java/awais/instagrabber/adapters/SliderCallbackAdapter.java +++ b/app/src/main/java/awais/instagrabber/adapters/SliderCallbackAdapter.java @@ -1,11 +1,17 @@ package awais.instagrabber.adapters; +import android.view.View; + +import com.google.android.exoplayer2.ui.StyledPlayerView; + +import awais.instagrabber.repositories.responses.Media; + public class SliderCallbackAdapter implements SliderItemsAdapter.SliderCallback { @Override public void onThumbnailLoaded(final int position) {} @Override - public void onItemClicked(final int position) {} + public void onItemClicked(final int position, final Media media, final View view) {} @Override public void onPlayerPlay(final int position) {} @@ -15,4 +21,12 @@ public class SliderCallbackAdapter implements SliderItemsAdapter.SliderCallback @Override public void onPlayerRelease(final int position) {} + + @Override + public void onFullScreenModeChanged(final boolean isFullScreen, final StyledPlayerView playerView) {} + + @Override + public boolean isInFullScreen() { + return false; + } } diff --git a/app/src/main/java/awais/instagrabber/adapters/SliderItemsAdapter.java b/app/src/main/java/awais/instagrabber/adapters/SliderItemsAdapter.java index 615bff38..2d036fb1 100644 --- a/app/src/main/java/awais/instagrabber/adapters/SliderItemsAdapter.java +++ b/app/src/main/java/awais/instagrabber/adapters/SliderItemsAdapter.java @@ -1,16 +1,18 @@ package awais.instagrabber.adapters; import android.view.LayoutInflater; +import android.view.View; import android.view.ViewGroup; import androidx.annotation.NonNull; import androidx.recyclerview.widget.DiffUtil; import androidx.recyclerview.widget.ListAdapter; +import com.google.android.exoplayer2.ui.StyledPlayerView; + import awais.instagrabber.adapters.viewholder.SliderItemViewHolder; import awais.instagrabber.adapters.viewholder.SliderPhotoViewHolder; import awais.instagrabber.adapters.viewholder.SliderVideoViewHolder; -import awais.instagrabber.customviews.VerticalDragHelper; import awais.instagrabber.databinding.ItemSliderPhotoBinding; import awais.instagrabber.databinding.LayoutVideoPlayerWithThumbnailBinding; import awais.instagrabber.models.enums.MediaItemType; @@ -18,10 +20,8 @@ import awais.instagrabber.repositories.responses.Media; public final class SliderItemsAdapter extends ListAdapter { - private final VerticalDragHelper.OnVerticalDragListener onVerticalDragListener; private final boolean loadVideoOnItemClick; private final SliderCallback sliderCallback; - // private final LayoutExoCustomControlsBinding controlsBinding; private static final DiffUtil.ItemCallback DIFF_CALLBACK = new DiffUtil.ItemCallback() { @Override @@ -35,15 +35,11 @@ public final class SliderItemsAdapter extends ListAdapter { - // if (sliderCallback != null) { - // sliderCallback.onItemClicked(position); - // } - // }); - binding.getRoot().setTapListener(new GestureDetector.SimpleOnGestureListener() { + final DoubleTapGestureListener tapListener = new DoubleTapGestureListener(binding.getRoot()) { @Override - public boolean onSingleTapUp(final MotionEvent e) { + public boolean onSingleTapConfirmed(final MotionEvent e) { if (sliderCallback != null) { - sliderCallback.onItemClicked(position); - return true; + sliderCallback.onItemClicked(position, model, binding.getRoot()); } - return false; + return super.onSingleTapConfirmed(e); } - }); + }; + binding.getRoot().setTapListener(tapListener); final AnimatedZoomableController zoomableController = AnimatedZoomableController.newInstance(); zoomableController.setMaxScaleFactor(3f); binding.getRoot().setZoomableController(zoomableController); - if (onVerticalDragListener != null) { - binding.getRoot().setOnVerticalDragListener(onVerticalDragListener); - } + binding.getRoot().setZoomingEnabled(true); } - - // private void setDimensions(final FeedModel feedModel, final int spanCount, final boolean animate) { - // final ViewGroup.LayoutParams layoutParams = binding.imageViewer.getLayoutParams(); - // final int deviceWidth = Utils.displayMetrics.widthPixels; - // final int spanWidth = deviceWidth / spanCount; - // final int spanHeight = NumberUtils.getResultingHeight(spanWidth, feedModel.getImageHeight(), feedModel.getImageWidth()); - // final int width = spanWidth == 0 ? deviceWidth : spanWidth; - // final int height = spanHeight == 0 ? deviceWidth + 1 : spanHeight; - // if (animate) { - // Animation animation = AnimationUtils.expand( - // binding.imageViewer, - // layoutParams.width, - // layoutParams.height, - // width, - // height, - // new Animation.AnimationListener() { - // @Override - // public void onAnimationStart(final Animation animation) { - // showOrHideDetails(spanCount); - // } - // - // @Override - // public void onAnimationEnd(final Animation animation) { - // // showOrHideDetails(spanCount); - // } - // - // @Override - // public void onAnimationRepeat(final Animation animation) { - // - // } - // }); - // binding.imageViewer.startAnimation(animation); - // } else { - // layoutParams.width = width; - // layoutParams.height = height; - // binding.imageViewer.requestLayout(); - // } - // } - // - // private void showOrHideDetails(final int spanCount) { - // if (spanCount == 1) { - // binding.itemFeedTop.getRoot().setVisibility(View.VISIBLE); - // binding.itemFeedBottom.getRoot().setVisibility(View.VISIBLE); - // } else { - // binding.itemFeedTop.getRoot().setVisibility(View.GONE); - // binding.itemFeedBottom.getRoot().setVisibility(View.GONE); - // } - // } } diff --git a/app/src/main/java/awais/instagrabber/adapters/viewholder/SliderVideoViewHolder.java b/app/src/main/java/awais/instagrabber/adapters/viewholder/SliderVideoViewHolder.java index d22afacd..3624d7ef 100644 --- a/app/src/main/java/awais/instagrabber/adapters/viewholder/SliderVideoViewHolder.java +++ b/app/src/main/java/awais/instagrabber/adapters/viewholder/SliderVideoViewHolder.java @@ -7,10 +7,11 @@ import android.view.ViewGroup; import androidx.annotation.NonNull; +import com.google.android.exoplayer2.ui.StyledPlayerView; + import java.util.List; import awais.instagrabber.adapters.SliderItemsAdapter; -import awais.instagrabber.customviews.VerticalDragHelper; import awais.instagrabber.customviews.VideoPlayerCallbackAdapter; import awais.instagrabber.customviews.VideoPlayerViewHelper; import awais.instagrabber.databinding.LayoutVideoPlayerWithThumbnailBinding; @@ -27,40 +28,23 @@ public class SliderVideoViewHolder extends SliderItemViewHolder { private static final String TAG = "SliderVideoViewHolder"; private final LayoutVideoPlayerWithThumbnailBinding binding; - // private final LayoutExoCustomControlsBinding controlsBinding; private final boolean loadVideoOnItemClick; - private final GestureDetector.OnGestureListener videoPlayerViewGestureListener = new GestureDetector.SimpleOnGestureListener() { - @Override - public boolean onSingleTapConfirmed(final MotionEvent e) { - binding.playerView.performClick(); - return true; - } - }; private VideoPlayerViewHelper videoPlayerViewHelper; @SuppressLint("ClickableViewAccessibility") public SliderVideoViewHolder(@NonNull final LayoutVideoPlayerWithThumbnailBinding binding, - final VerticalDragHelper.OnVerticalDragListener onVerticalDragListener, - // final LayoutExoCustomControlsBinding controlsBinding, final boolean loadVideoOnItemClick) { super(binding.getRoot()); this.binding = binding; - // this.controlsBinding = controlsBinding; this.loadVideoOnItemClick = loadVideoOnItemClick; - // if (onVerticalDragListener != null) { - // final VerticalDragHelper thumbnailVerticalDragHelper = new VerticalDragHelper(binding.thumbnailParent); - // final VerticalDragHelper playerVerticalDragHelper = new VerticalDragHelper(binding.playerView); - // thumbnailVerticalDragHelper.setOnVerticalDragListener(onVerticalDragListener); - // playerVerticalDragHelper.setOnVerticalDragListener(onVerticalDragListener); - // binding.thumbnailParent.setOnTouchListener((v, event) -> { - // final boolean onDragTouch = thumbnailVerticalDragHelper.onDragTouch(event); - // if (onDragTouch) { - // return true; - // } - // return thumbnailVerticalDragHelper.onGestureTouchEvent(event); - // }); - // } + final GestureDetector.OnGestureListener videoPlayerViewGestureListener = new GestureDetector.SimpleOnGestureListener() { + @Override + public boolean onSingleTapConfirmed(final MotionEvent e) { + binding.playerView.performClick(); + return true; + } + }; final GestureDetector gestureDetector = new GestureDetector(itemView.getContext(), videoPlayerViewGestureListener); binding.playerView.setOnTouchListener((v, event) -> { gestureDetector.onTouchEvent(event); @@ -77,7 +61,7 @@ public class SliderVideoViewHolder extends SliderItemViewHolder { @Override public void onThumbnailClick() { if (sliderCallback != null) { - sliderCallback.onItemClicked(position); + sliderCallback.onItemClicked(position, media, binding.getRoot()); } } @@ -120,6 +104,21 @@ public class SliderVideoViewHolder extends SliderItemViewHolder { sliderCallback.onPlayerRelease(position); } } + + @Override + public void onFullScreenModeChanged(final boolean isFullScreen, final StyledPlayerView playerView) { + if (sliderCallback != null) { + sliderCallback.onFullScreenModeChanged(isFullScreen, playerView); + } + } + + @Override + public boolean isInFullScreen() { + if (sliderCallback != null) { + return sliderCallback.isInFullScreen(); + } + return false; + } }; final float aspectRatio = (float) media.getOriginalWidth() / media.getOriginalHeight(); String videoUrl = null; @@ -138,16 +137,10 @@ public class SliderVideoViewHolder extends SliderItemViewHolder { aspectRatio, ResponseBodyUtils.getThumbUrl(media), loadVideoOnItemClick, - // controlsBinding, videoPlayerCallback); - // binding.itemFeedBottom.btnMute.setOnClickListener(v -> { - // final float newVol = videoPlayerViewHelper.toggleMute(); - // setMuteIcon(newVol); - // Utils.sessionVolumeFull = newVol == 1f; - // }); binding.playerView.setOnClickListener(v -> { if (sliderCallback != null) { - sliderCallback.onItemClicked(position); + sliderCallback.onItemClicked(position, media, binding.getRoot()); } }); } @@ -161,62 +154,4 @@ public class SliderVideoViewHolder extends SliderItemViewHolder { if (videoPlayerViewHelper == null) return; videoPlayerViewHelper.releasePlayer(); } - - // public void resetPlayerTimeline() { - // if (videoPlayerViewHelper == null) return; - // videoPlayerViewHelper.resetTimeline(); - // } - // - // public void removeCallbacks() { - // if (videoPlayerViewHelper == null) return; - // videoPlayerViewHelper.removeCallbacks(); - // } - - // private void setDimensions(final FeedModel feedModel, final int spanCount, final boolean animate) { - // final ViewGroup.LayoutParams layoutParams = binding.imageViewer.getLayoutParams(); - // final int deviceWidth = Utils.displayMetrics.widthPixels; - // final int spanWidth = deviceWidth / spanCount; - // final int spanHeight = NumberUtils.getResultingHeight(spanWidth, feedModel.getImageHeight(), feedModel.getImageWidth()); - // final int width = spanWidth == 0 ? deviceWidth : spanWidth; - // final int height = spanHeight == 0 ? deviceWidth + 1 : spanHeight; - // if (animate) { - // Animation animation = AnimationUtils.expand( - // binding.imageViewer, - // layoutParams.width, - // layoutParams.height, - // width, - // height, - // new Animation.AnimationListener() { - // @Override - // public void onAnimationStart(final Animation animation) { - // showOrHideDetails(spanCount); - // } - // - // @Override - // public void onAnimationEnd(final Animation animation) { - // // showOrHideDetails(spanCount); - // } - // - // @Override - // public void onAnimationRepeat(final Animation animation) { - // - // } - // }); - // binding.imageViewer.startAnimation(animation); - // } else { - // layoutParams.width = width; - // layoutParams.height = height; - // binding.imageViewer.requestLayout(); - // } - // } - // - // private void showOrHideDetails(final int spanCount) { - // if (spanCount == 1) { - // binding.itemFeedTop.getRoot().setVisibility(View.VISIBLE); - // binding.itemFeedBottom.getRoot().setVisibility(View.VISIBLE); - // } else { - // binding.itemFeedTop.getRoot().setVisibility(View.GONE); - // binding.itemFeedBottom.getRoot().setVisibility(View.GONE); - // } - // } } diff --git a/app/src/main/java/awais/instagrabber/adapters/viewholder/feed/FeedSliderViewHolder.java b/app/src/main/java/awais/instagrabber/adapters/viewholder/feed/FeedSliderViewHolder.java index 3d5b5587..6931c851 100644 --- a/app/src/main/java/awais/instagrabber/adapters/viewholder/feed/FeedSliderViewHolder.java +++ b/app/src/main/java/awais/instagrabber/adapters/viewholder/feed/FeedSliderViewHolder.java @@ -45,9 +45,9 @@ public class FeedSliderViewHolder extends FeedItemViewHolder { final String text = "1/" + sliderItemLen; binding.mediaCounter.setText(text); binding.mediaList.setOffscreenPageLimit(1); - final SliderItemsAdapter adapter = new SliderItemsAdapter(null, false, new SliderCallbackAdapter() { + final SliderItemsAdapter adapter = new SliderItemsAdapter(false, new SliderCallbackAdapter() { @Override - public void onItemClicked(final int position) { + public void onItemClicked(final int position, final Media media, final View view) { feedItemCallback.onSliderClick(feedModel, position); } }); diff --git a/app/src/main/java/awais/instagrabber/customviews/VideoPlayerCallbackAdapter.java b/app/src/main/java/awais/instagrabber/customviews/VideoPlayerCallbackAdapter.java index 30b9bbca..dd75c15f 100644 --- a/app/src/main/java/awais/instagrabber/customviews/VideoPlayerCallbackAdapter.java +++ b/app/src/main/java/awais/instagrabber/customviews/VideoPlayerCallbackAdapter.java @@ -1,5 +1,7 @@ package awais.instagrabber.customviews; +import com.google.android.exoplayer2.ui.StyledPlayerView; + public class VideoPlayerCallbackAdapter implements VideoPlayerViewHelper.VideoPlayerCallback { @Override public void onThumbnailLoaded() {} @@ -18,4 +20,12 @@ public class VideoPlayerCallbackAdapter implements VideoPlayerViewHelper.VideoPl @Override public void onRelease() {} + + @Override + public void onFullScreenModeChanged(final boolean isFullScreen, final StyledPlayerView playerView) {} + + @Override + public boolean isInFullScreen() { + return false; + } } diff --git a/app/src/main/java/awais/instagrabber/customviews/VideoPlayerViewHelper.java b/app/src/main/java/awais/instagrabber/customviews/VideoPlayerViewHelper.java index 84d2305e..6ce21a77 100644 --- a/app/src/main/java/awais/instagrabber/customviews/VideoPlayerViewHelper.java +++ b/app/src/main/java/awais/instagrabber/customviews/VideoPlayerViewHelper.java @@ -1,15 +1,19 @@ package awais.instagrabber.customviews; import android.content.Context; +import android.content.res.ColorStateList; +import android.content.res.Resources; import android.graphics.drawable.Animatable; import android.net.Uri; import android.os.Looper; import android.util.Log; import android.view.View; import android.view.ViewGroup; +import android.widget.ImageView; import androidx.annotation.NonNull; -import androidx.appcompat.widget.PopupMenu; +import androidx.annotation.Nullable; +import androidx.appcompat.widget.AppCompatImageButton; import com.facebook.drawee.backends.pipeline.Fresco; import com.facebook.drawee.backends.pipeline.PipelineDraweeControllerBuilder; @@ -23,18 +27,23 @@ import com.google.android.exoplayer2.Player; import com.google.android.exoplayer2.SimpleExoPlayer; import com.google.android.exoplayer2.audio.AudioListener; import com.google.android.exoplayer2.source.ProgressiveMediaSource; +import com.google.android.exoplayer2.source.TrackGroupArray; +import com.google.android.exoplayer2.trackselection.TrackSelectionArray; import com.google.android.exoplayer2.ui.AspectRatioFrameLayout; +import com.google.android.exoplayer2.ui.StyledPlayerControlView; +import com.google.android.exoplayer2.ui.StyledPlayerView; import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory; -import com.google.android.material.button.MaterialButton; + +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; import awais.instagrabber.R; import awais.instagrabber.databinding.LayoutVideoPlayerWithThumbnailBinding; import awais.instagrabber.utils.Utils; public class VideoPlayerViewHelper implements Player.EventListener { - private static final String TAG = "VideoPlayerViewHelper"; - // private static final long INITIAL_DELAY = 0; - // private static final long RECURRING_DELAY = 60; + private static final String TAG = VideoPlayerViewHelper.class.getSimpleName(); private final Context context; private final LayoutVideoPlayerWithThumbnailBinding binding; @@ -42,74 +51,20 @@ public class VideoPlayerViewHelper implements Player.EventListener { private final float thumbnailAspectRatio; private final String thumbnailUrl; private final boolean loadPlayerOnClick; - // private final LayoutExoCustomControlsBinding controlsBinding; private final VideoPlayerCallback videoPlayerCallback; private final String videoUrl; private final DefaultDataSourceFactory dataSourceFactory; private SimpleExoPlayer player; - private PopupMenu speedPopup; - // private PositionCheckRunnable positionChecker; - // private Handler positionUpdateHandler; + private AppCompatImageButton mute; - // private final Player.EventListener listener = new Player.EventListener() { - // @Override - // public void onPlaybackStateChanged(final int state) { - // // switch (state) { - // // case Player.STATE_BUFFERING: - // // case STATE_IDLE: - // // case STATE_ENDED: - // // positionUpdateHandler.removeCallbacks(positionChecker); - // // return; - // // case STATE_READY: - // // setupTimeline(); - // // positionUpdateHandler.postDelayed(positionChecker, INITIAL_DELAY); - // // break; - // // } - // } - // - // @Override - // public void onPlayWhenReadyChanged(final boolean playWhenReady, final int reason) { - // // updatePlayPauseDrawable(playWhenReady); - // // if (positionUpdateHandler == null || positionChecker == null) return; - // // if (playWhenReady) { - // // positionUpdateHandler.removeCallbacks(positionChecker); - // // positionUpdateHandler.postDelayed(positionChecker, INITIAL_DELAY); - // // } - // } - // }; private final AudioListener audioListener = new AudioListener() { @Override public void onVolumeChanged(final float volume) { updateMuteIcon(volume); } }; - // private final Slider.OnChangeListener onChangeListener = (slider, value, fromUser) -> { - // if (!fromUser) return; - // long actualValue = (long) value; - // if (actualValue < 0) { - // actualValue = 0; - // } else if (actualValue > player.getDuration()) { - // actualValue = player.getDuration(); - // } - // player.seekTo(actualValue); - // }; - // private final View.OnClickListener onClickListener = v -> player.setPlayWhenReady(!player.getPlayWhenReady()); - // // private final LabelFormatter labelFormatter = value -> TextUtils.millisToTimeString((long) value); private final View.OnClickListener muteOnClickListener = v -> toggleMute(); - private MaterialButton mute; - // private final View.OnClickListener rewOnClickListener = v -> { - // final long positionMs = player.getCurrentPosition() - 5000; - // player.seekTo(positionMs < 0 ? 0 : positionMs); - // }; - // private final View.OnClickListener ffOnClickListener = v -> { - // long positionMs = player.getCurrentPosition() + 5000; - // long duration = player.getDuration(); - // if (duration == TIME_UNSET) { - // duration = 0; - // } - // player.seekTo(Math.min(positionMs, duration)); - // }; - // private final View.OnClickListener showMenu = this::showMenu; + private Object layoutManager; public VideoPlayerViewHelper(@NonNull final Context context, @NonNull final LayoutVideoPlayerWithThumbnailBinding binding, @@ -118,7 +73,6 @@ public class VideoPlayerViewHelper implements Player.EventListener { final float thumbnailAspectRatio, final String thumbnailUrl, final boolean loadPlayerOnClick, - // final LayoutExoCustomControlsBinding controlsBinding, final VideoPlayerCallback videoPlayerCallback) { this.context = context; this.binding = binding; @@ -126,7 +80,6 @@ public class VideoPlayerViewHelper implements Player.EventListener { this.thumbnailAspectRatio = thumbnailAspectRatio; this.thumbnailUrl = thumbnailUrl; this.loadPlayerOnClick = loadPlayerOnClick; - // this.controlsBinding = controlsBinding; this.videoPlayerCallback = videoPlayerCallback; this.videoUrl = videoUrl; this.dataSourceFactory = new DefaultDataSourceFactory(binding.getRoot().getContext(), "instagram"); @@ -143,7 +96,6 @@ public class VideoPlayerViewHelper implements Player.EventListener { } }); setThumbnail(); - // setupControls(); } private void setThumbnail() { @@ -196,11 +148,6 @@ public class VideoPlayerViewHelper implements Player.EventListener { player = new SimpleExoPlayer.Builder(context) .setLooper(Looper.getMainLooper()) .build(); - // positionUpdateHandler = new Handler(); - // positionChecker = new PositionCheckRunnable(positionUpdateHandler, - // player, - // controlsBinding.timeline, - // controlsBinding.fromTime); player.addListener(this); player.addAudioListener(audioListener); player.setVolume(initialVolume); @@ -210,138 +157,118 @@ public class VideoPlayerViewHelper implements Player.EventListener { final MediaItem mediaItem = MediaItem.fromUri(videoUrl); final ProgressiveMediaSource mediaSource = sourceFactory.createMediaSource(mediaItem); player.setMediaSource(mediaSource); - // setupControls(); player.prepare(); binding.playerView.setPlayer(player); - // binding.playerView.setShowFastForwardButton(false); - // binding.playerView.setShowRewindButton(false); - binding.playerView.setResizeMode(AspectRatioFrameLayout.RESIZE_MODE_FIXED_HEIGHT); + binding.playerView.setResizeMode(AspectRatioFrameLayout.RESIZE_MODE_FIT); binding.playerView.setShowNextButton(false); binding.playerView.setShowPreviousButton(false); - // binding.controls.setPlayer(player); - mute = binding.playerView.findViewById(R.id.mute); - // mute = binding.controls.findViewById(R.id.mute); - if (mute != null) { - mute.setOnClickListener(muteOnClickListener); - } - updateMuteIcon(player.getVolume()); + binding.playerView.setControllerOnFullScreenModeChangedListener(isFullScreen -> { + if (videoPlayerCallback == null) return; + videoPlayerCallback.onFullScreenModeChanged(isFullScreen, binding.playerView); + }); + setupControllerView(); } - // private void setupControls() { - // if (controlsBinding == null) return; - // // binding.playerView.setUseController(false); - // if (player == null) { - // // enableControls(false); - // // controlsBinding.playPause.setEnabled(true); - // // controlsBinding.playPause.setOnClickListener(new NoPlayerPlayPauseClickListener(binding.thumbnailParent)); - // return; - // } - // // enableControls(true); - // // updatePlayPauseDrawable(player.getPlayWhenReady()); - // // updateMuteIcon(player.getVolume()); - // player.addListener(listener); - // // player.addAudioListener(audioListener); - // // controlsBinding.timeline.addOnChangeListener(onChangeListener); - // // controlsBinding.timeline.setLabelFormatter(labelFormatter); - // // controlsBinding.playPause.setOnClickListener(onClickListener); - // // controlsBinding.mute.setOnClickListener(muteOnClickListener); - // // controlsBinding.rewWithAmount.setOnClickListener(rewOnClickListener); - // // controlsBinding.ffWithAmount.setOnClickListener(ffOnClickListener); - // // controlsBinding.speed.setOnClickListener(showMenu); - // } + private void setupControllerView() { + try { + final StyledPlayerControlView controllerView = getStyledPlayerControlView(); + if (controllerView == null) return; + layoutManager = setControlViewLayoutManager(controllerView); + if (videoPlayerCallback != null && videoPlayerCallback.isInFullScreen()) { + setControllerViewToFullScreenMode(controllerView); + } + final ViewGroup exoBasicControls = controllerView.findViewById(R.id.exo_basic_controls); + if (exoBasicControls == null) return; + mute = new AppCompatImageButton(context); + final Resources resources = context.getResources(); + if (resources == null) return; + final int width = resources.getDimensionPixelSize(R.dimen.exo_small_icon_width); + final int height = resources.getDimensionPixelSize(R.dimen.exo_small_icon_height); + final int margin = resources.getDimensionPixelSize(R.dimen.exo_small_icon_horizontal_margin); + final int paddingHorizontal = resources.getDimensionPixelSize(R.dimen.exo_small_icon_padding_horizontal); + final int paddingVertical = resources.getDimensionPixelSize(R.dimen.exo_small_icon_padding_vertical); + final ViewGroup.MarginLayoutParams layoutParams = new ViewGroup.MarginLayoutParams(width, height); + layoutParams.setMargins(margin, 0, margin, 0); + mute.setLayoutParams(layoutParams); + mute.setPadding(paddingHorizontal, paddingVertical, paddingHorizontal, paddingVertical); + mute.setScaleType(ImageView.ScaleType.FIT_XY); + mute.setBackgroundResource(Utils.getAttrResId(context, android.R.attr.selectableItemBackground)); + mute.setImageTintList(ColorStateList.valueOf(resources.getColor(R.color.white))); + updateMuteIcon(player.getVolume()); + exoBasicControls.addView(mute, 0); + mute.setOnClickListener(muteOnClickListener); + } catch (Exception e) { + Log.e(TAG, "loadPlayer: ", e); + } + } - // private void setupTimeline() { - // final long duration = player.getDuration(); - // controlsBinding.timeline.setEnabled(true); - // controlsBinding.timeline.setValueFrom(0); - // controlsBinding.timeline.setValueTo(duration); - // controlsBinding.fromTime.setText(TextUtils.millisToTimeString(0)); - // controlsBinding.toTime.setText(TextUtils.millisToTimeString(duration)); - // } + @Nullable + private Object setControlViewLayoutManager(@NonNull final StyledPlayerControlView controllerView) + throws NoSuchFieldException, IllegalAccessException { + final Field controlViewLayoutManagerField = controllerView.getClass().getDeclaredField("controlViewLayoutManager"); + controlViewLayoutManagerField.setAccessible(true); + return controlViewLayoutManagerField.get(controllerView); + } - // private void enableControls(final boolean enable) { - // controlsBinding.speed.setEnabled(enable); - // controlsBinding.speed.setClickable(enable); - // controlsBinding.mute.setEnabled(enable); - // controlsBinding.mute.setClickable(enable); - // controlsBinding.ffWithAmount.setEnabled(enable); - // controlsBinding.ffWithAmount.setClickable(enable); - // controlsBinding.rewWithAmount.setEnabled(enable); - // controlsBinding.rewWithAmount.setClickable(enable); - // // controlsBinding.fromTime.setEnabled(enable); - // // controlsBinding.toTime.setEnabled(enable); - // controlsBinding.playPause.setEnabled(enable); - // controlsBinding.playPause.setClickable(enable); - // // controlsBinding.timeline.setEnabled(enable); - // } + private void setControllerViewToFullScreenMode(@NonNull final StyledPlayerControlView controllerView) + throws NoSuchFieldException, IllegalAccessException, NoSuchMethodException, InvocationTargetException { + // Exoplayer doesn't expose the fullscreen state, so using reflection + final Field fullScreenButtonField = controllerView.getClass().getDeclaredField("fullScreenButton"); + fullScreenButtonField.setAccessible(true); + final ImageView fullScreenButton = (ImageView) fullScreenButtonField.get(controllerView); + final Field isFullScreen = controllerView.getClass().getDeclaredField("isFullScreen"); + isFullScreen.setAccessible(true); + isFullScreen.set(controllerView, true); + final Method updateFullScreenButtonForState = controllerView + .getClass() + .getDeclaredMethod("updateFullScreenButtonForState", ImageView.class, boolean.class); + updateFullScreenButtonForState.setAccessible(true); + updateFullScreenButtonForState.invoke(controllerView, fullScreenButton, true); - // public void showMenu(View anchor) { - // PopupMenu popup = getPopupMenu(anchor); - // popup.show(); - // } + } - // @NonNull - // private PopupMenu getPopupMenu(final View anchor) { - // if (speedPopup != null) { - // return speedPopup; - // } - // final ContextThemeWrapper themeWrapper = new ContextThemeWrapper(context, R.style.popupMenuStyle); - // // final ContextThemeWrapper themeWrapper = new ContextThemeWrapper(context, R.style.Widget_MaterialComponents_PopupMenu_Exoplayer); - // speedPopup = new PopupMenu(themeWrapper, anchor); - // speedPopup.getMenuInflater().inflate(R.menu.speed_menu, speedPopup.getMenu()); - // speedPopup.setOnMenuItemClickListener(item -> { - // float nextSpeed; - // int textResId; - // int itemId = item.getItemId(); - // if (itemId == R.id.pt_two_five_x) { - // nextSpeed = 0.25f; - // textResId = R.string.pt_two_five_x; - // } else if (itemId == R.id.pt_five_x) { - // nextSpeed = 0.5f; - // textResId = R.string.pt_five_x; - // } else if (itemId == R.id.pt_seven_five_x) { - // nextSpeed = 0.75f; - // textResId = R.string.pt_seven_five_x; - // } else if (itemId == R.id.one_x) { - // nextSpeed = 1f; - // textResId = R.string.one_x; - // } else if (itemId == R.id.one_pt_two_five_x) { - // nextSpeed = 1.25f; - // textResId = R.string.one_pt_two_five_x; - // } else if (itemId == R.id.one_pt_five_x) { - // nextSpeed = 1.5f; - // textResId = R.string.one_pt_five_x; - // } else if (itemId == R.id.two_x) { - // nextSpeed = 2f; - // textResId = R.string.two_x; - // } else { - // nextSpeed = 1; - // textResId = R.string.one_x; - // } - // player.setPlaybackParameters(new PlaybackParameters(nextSpeed)); - // controlsBinding.speed.setText(textResId); - // return true; - // }); - // return speedPopup; - // } + @Nullable + private StyledPlayerControlView getStyledPlayerControlView() throws NoSuchFieldException, IllegalAccessException { + final Field controller = binding.playerView.getClass().getDeclaredField("controller"); + controller.setAccessible(true); + return (StyledPlayerControlView) controller.get(binding.playerView); + } + + @Override + public void onTracksChanged(@NonNull TrackGroupArray trackGroups, @NonNull TrackSelectionArray trackSelections) { + if (trackGroups.isEmpty()) { + setHasAudio(false); + return; + } + boolean hasAudio = false; + for (int i = 0; i < trackGroups.length; i++) { + for (int g = 0; g < trackGroups.get(i).length; g++) { + final String sampleMimeType = trackGroups.get(i).getFormat(g).sampleMimeType; + if (sampleMimeType != null && sampleMimeType.contains("audio")) { + hasAudio = true; + break; + } + } + } + setHasAudio(hasAudio); + } + + private void setHasAudio(final boolean hasAudio) { + if (mute == null) return; + mute.setEnabled(hasAudio); + mute.setAlpha(hasAudio ? 1f : 0.5f); + updateMuteIcon(hasAudio ? 1f : 0f); + } private void updateMuteIcon(final float volume) { if (mute == null) return; if (volume == 0) { - mute.setIconResource(R.drawable.ic_volume_off_24_states); + mute.setImageResource(R.drawable.ic_volume_off_24); return; } - mute.setIconResource(R.drawable.ic_volume_up_24_states); + mute.setImageResource(R.drawable.ic_volume_up_24); } - // private void updatePlayPauseDrawable(final boolean playWhenReady) { - // if (playWhenReady) { - // controlsBinding.playPause.setIconResource(R.drawable.ic_pause_24); - // return; - // } - // controlsBinding.playPause.setIconResource(R.drawable.ic_play_states); - // } - @Override public void onPlayWhenReadyChanged(final boolean playWhenReady, final int reason) { if (videoPlayerCallback == null) return; @@ -359,18 +286,18 @@ public class VideoPlayerViewHelper implements Player.EventListener { private void toggleMute() { if (player == null) return; + if (layoutManager != null) { + try { + final Method resetHideCallbacks = layoutManager.getClass().getDeclaredMethod("resetHideCallbacks"); + resetHideCallbacks.invoke(layoutManager); + } catch (Exception e) { + Log.e(TAG, "toggleMute: ", e); + } + } final float vol = player.getVolume() == 0f ? 1f : 0f; player.setVolume(vol); } - // public void togglePlayback() { - // if (player == null) return; - // final int playbackState = player.getPlaybackState(); - // if (playbackState == STATE_IDLE || playbackState == STATE_ENDED) return; - // final boolean playWhenReady = player.getPlayWhenReady(); - // player.setPlayWhenReady(!playWhenReady); - // } - public void releasePlayer() { if (videoPlayerCallback != null) { videoPlayerCallback.onRelease(); @@ -379,86 +306,14 @@ public class VideoPlayerViewHelper implements Player.EventListener { player.release(); player = null; } - // if (positionUpdateHandler != null) { - // if (positionChecker != null) { - // positionUpdateHandler.removeCallbacks(positionChecker); - // positionChecker = null; - // } - // positionUpdateHandler = null; - // } } public void pause() { if (player != null) { player.pause(); } - // if (positionUpdateHandler != null) { - // if (positionChecker != null) { - // positionUpdateHandler.removeCallbacks(positionChecker); - // } - // } } - // public void resetTimeline() { - // if (player == null) { - // enableControls(false); - // return; - // } - // setupTimeline(); - // final long currentPosition = player.getCurrentPosition(); - // controlsBinding.timeline.setValue(Math.min(currentPosition, player.getDuration())); - // setupControls(); - // } - - // public void removeCallbacks() { - // if (player != null) { - // player.removeListener(listener); - // player.removeAudioListener(audioListener); - // } - // controlsBinding.timeline.removeOnChangeListener(onChangeListener); - // controlsBinding.timeline.setLabelFormatter(null); - // controlsBinding.playPause.setOnClickListener(null); - // controlsBinding.mute.setOnClickListener(null); - // controlsBinding.rewWithAmount.setOnClickListener(null); - // controlsBinding.ffWithAmount.setOnClickListener(null); - // controlsBinding.speed.setOnClickListener(null); - // } - - // private static class PositionCheckRunnable implements Runnable { - // private final Handler positionUpdateHandler; - // private final SimpleExoPlayer player; - // private final Slider timeline; - // private final AppCompatTextView fromTime; - // - // public PositionCheckRunnable(final Handler positionUpdateHandler, - // final SimpleExoPlayer simpleExoPlayer, - // final Slider slider, - // final AppCompatTextView fromTime) { - // this.positionUpdateHandler = positionUpdateHandler; - // this.player = simpleExoPlayer; - // this.timeline = slider; - // this.fromTime = fromTime; - // } - // - // @Override - // public void run() { - // if (positionUpdateHandler == null) return; - // positionUpdateHandler.removeCallbacks(this); - // if (player == null) return; - // final long currentPosition = player.getCurrentPosition(); - // final long duration = player.getDuration(); - // if (duration == TIME_UNSET) { - // timeline.setValueFrom(0); - // timeline.setValueTo(0); - // timeline.setEnabled(false); - // return; - // } - // timeline.setValue(Math.min(currentPosition, duration)); - // fromTime.setText(TextUtils.millisToTimeString(currentPosition)); - // positionUpdateHandler.postDelayed(this, RECURRING_DELAY); - // } - // } - public interface VideoPlayerCallback { void onThumbnailLoaded(); @@ -471,5 +326,9 @@ public class VideoPlayerViewHelper implements Player.EventListener { void onPause(); void onRelease(); + + void onFullScreenModeChanged(boolean isFullScreen, final StyledPlayerView playerView); + + boolean isInFullScreen(); } } diff --git a/app/src/main/java/awais/instagrabber/fragments/PostViewV2Fragment.java b/app/src/main/java/awais/instagrabber/fragments/PostViewV2Fragment.java index fc3c4a7e..65315e35 100644 --- a/app/src/main/java/awais/instagrabber/fragments/PostViewV2Fragment.java +++ b/app/src/main/java/awais/instagrabber/fragments/PostViewV2Fragment.java @@ -6,6 +6,7 @@ import android.content.pm.PackageManager; import android.content.res.ColorStateList; import android.content.res.Resources; import android.graphics.Rect; +import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.net.Uri; import android.os.Bundle; @@ -14,15 +15,18 @@ import android.text.Spanned; import android.util.Log; import android.view.LayoutInflater; import android.view.MenuItem; +import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import android.widget.Toast; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.appcompat.app.ActionBar; import androidx.appcompat.content.res.AppCompatResources; import androidx.appcompat.view.ContextThemeWrapper; import androidx.appcompat.widget.PopupMenu; +import androidx.appcompat.widget.Toolbar; import androidx.constraintlayout.widget.ConstraintLayout; import androidx.core.content.PermissionChecker; import androidx.fragment.app.Fragment; @@ -44,6 +48,8 @@ import com.facebook.drawee.generic.GenericDraweeHierarchyBuilder; import com.facebook.drawee.interfaces.DraweeController; import com.facebook.imagepipeline.request.ImageRequest; import com.facebook.imagepipeline.request.ImageRequestBuilder; +import com.google.android.exoplayer2.ui.StyledPlayerView; +import com.google.android.material.appbar.CollapsingToolbarLayout; import com.google.android.material.snackbar.BaseTransientBottomBar; import com.google.android.material.snackbar.Snackbar; import com.skydoves.balloon.ArrowOrientation; @@ -59,6 +65,7 @@ import java.io.Serializable; import java.util.List; import awais.instagrabber.R; +import awais.instagrabber.activities.MainActivity; import awais.instagrabber.adapters.SliderCallbackAdapter; import awais.instagrabber.adapters.SliderItemsAdapter; import awais.instagrabber.adapters.viewholder.SliderVideoViewHolder; @@ -67,6 +74,7 @@ import awais.instagrabber.customviews.VideoPlayerCallbackAdapter; import awais.instagrabber.customviews.VideoPlayerViewHelper; import awais.instagrabber.customviews.drawee.AnimatedZoomableController; import awais.instagrabber.customviews.drawee.DoubleTapGestureListener; +import awais.instagrabber.customviews.drawee.ZoomableController; import awais.instagrabber.customviews.drawee.ZoomableDraweeView; import awais.instagrabber.databinding.DialogPostViewBinding; import awais.instagrabber.databinding.LayoutPostViewBottomBinding; @@ -117,6 +125,12 @@ public class PostViewV2Fragment extends Fragment implements EditTextDialogFragme @Nullable private ViewPager2 sliderParent; private LayoutPostViewBottomBinding bottom; + private View postView; + private int originalHeight; + private int originalSystemUi; + private boolean isInFullScreenMode; + private StyledPlayerView playerView; + private int playerViewOriginalHeight; private final Observer backStackSavedStateObserver = result -> { if (result == null) return; @@ -127,6 +141,7 @@ public class PostViewV2Fragment extends Fragment implements EditTextDialogFragme // clear result backStackSavedStateResultLiveData.postValue(null); }; + private Drawable originalRootBackground; public void setOnDeleteListener(final OnDeleteListener onDeleteListener) { if (onDeleteListener == null) return; @@ -197,6 +212,7 @@ public class PostViewV2Fragment extends Fragment implements EditTextDialogFragme @Override public void onDestroyView() { super.onDestroyView(); + showSystemUI(); final Media media = viewModel.getMedia(); if (media == null) return; switch (media.getMediaType()) { @@ -753,7 +769,7 @@ public class PostViewV2Fragment extends Fragment implements EditTextDialogFragme } private void setupPostImage() { - binding.mediaCounter.setVisibility(View.GONE); + // binding.mediaCounter.setVisibility(View.GONE); final Context context = getContext(); if (context == null) return; final Resources resources = context.getResources(); @@ -762,12 +778,14 @@ public class PostViewV2Fragment extends Fragment implements EditTextDialogFragme final String imageUrl = ResponseBodyUtils.getImageUrl(media); if (TextUtils.isEmpty(imageUrl)) return; final ZoomableDraweeView postImage = new ZoomableDraweeView(context); + postView = postImage; final NullSafePair widthHeight = NumberUtils.calculateWidthHeight(media.getOriginalHeight(), media.getOriginalWidth(), (int) (Utils.displayMetrics.heightPixels * 0.8), Utils.displayMetrics.widthPixels); - final int height = widthHeight.second; - final ConstraintLayout.LayoutParams layoutParams = new ConstraintLayout.LayoutParams(ConstraintLayout.LayoutParams.MATCH_PARENT, height); + originalHeight = widthHeight.second; + final ConstraintLayout.LayoutParams layoutParams = new ConstraintLayout.LayoutParams(ConstraintLayout.LayoutParams.MATCH_PARENT, + originalHeight); layoutParams.topToBottom = binding.topBarrier.getId(); layoutParams.bottomToTop = bottom.buttonsTopBarrier.getId(); layoutParams.startToStart = ConstraintLayout.LayoutParams.PARENT_ID; @@ -788,10 +806,22 @@ public class PostViewV2Fragment extends Fragment implements EditTextDialogFragme zoomableController.setGestureZoomEnabled(true); zoomableController.setEnabled(true); postImage.setZoomingEnabled(true); - postImage.setTapListener(new DoubleTapGestureListener(postImage)); + final DoubleTapGestureListener tapListener = new DoubleTapGestureListener(postImage) { + @Override + public boolean onSingleTapConfirmed(final MotionEvent e) { + if (!isInFullScreenMode) { + zoomableController.reset(); + hideSystemUI(); + } else { + showSystemUI(); + binding.getRoot().postDelayed(zoomableController::reset, 500); + } + return super.onSingleTapConfirmed(e); + } + }; + postImage.setTapListener(tapListener); + // postImage.setAllowTouchInterceptionWhileZoomed(true); binding.contentRoot.addView(postImage, 0); - // binding.postImage.setAllowTouchInterceptionWhileZoomed(true); - // binding.postImage.setOnVerticalDragListener(onVerticalDragListener); } private void setupSlider() { @@ -818,13 +848,15 @@ public class PostViewV2Fragment extends Fragment implements EditTextDialogFragme maxHW.second, (int) (Utils.displayMetrics.heightPixels * 0.8), Utils.displayMetrics.widthPixels); + originalHeight = widthHeight.second; final ConstraintLayout.LayoutParams layoutParams = new ConstraintLayout.LayoutParams(ConstraintLayout.LayoutParams.MATCH_PARENT, - widthHeight.second); + originalHeight); layoutParams.topToBottom = binding.topBarrier.getId(); layoutParams.bottomToTop = bottom.buttonsTopBarrier.getId(); layoutParams.startToStart = ConstraintLayout.LayoutParams.PARENT_ID; layoutParams.endToEnd = ConstraintLayout.LayoutParams.PARENT_ID; sliderParent.setLayoutParams(layoutParams); + postView = sliderParent; binding.contentRoot.addView(sliderParent, 0); final boolean hasVideo = media.getCarouselMedia() @@ -841,16 +873,23 @@ public class PostViewV2Fragment extends Fragment implements EditTextDialogFragme }); } } - sliderItemsAdapter = new SliderItemsAdapter(null, true, new SliderCallbackAdapter() { + sliderItemsAdapter = new SliderItemsAdapter(true, new SliderCallbackAdapter() { @Override - public void onThumbnailLoaded(final int position) { - if (position != 0) return; - startPostponedEnterTransition(); - } - - @Override - public void onItemClicked(final int position) { - // toggleDetails(); + public void onItemClicked(final int position, final Media media, final View view) { + if (media == null + || media.getMediaType() != MediaItemType.MEDIA_TYPE_IMAGE + || !(view instanceof ZoomableDraweeView)) { + return; + } + final ZoomableController zoomableController = ((ZoomableDraweeView) view).getZoomableController(); + if (!(zoomableController instanceof AnimatedZoomableController)) return; + if (!isInFullScreenMode) { + ((AnimatedZoomableController) zoomableController).reset(); + hideSystemUI(); + return; + } + showSystemUI(); + binding.getRoot().postDelayed(((AnimatedZoomableController) zoomableController)::reset, 500); } @Override @@ -877,6 +916,21 @@ public class PostViewV2Fragment extends Fragment implements EditTextDialogFragme if (activity == null) return; Utils.disableKeepScreenOn(activity); } + + @Override + public void onFullScreenModeChanged(final boolean isFullScreen, final StyledPlayerView playerView) { + PostViewV2Fragment.this.playerView = playerView; + if (isFullScreen) { + hideSystemUI(); + return; + } + showSystemUI(); + } + + @Override + public boolean isInFullScreen() { + return isInFullScreenMode; + } }); sliderParent.setAdapter(sliderItemsAdapter); if (sliderPosition >= 0 && sliderPosition < media.getCarouselMedia().size()) { @@ -981,12 +1035,14 @@ public class PostViewV2Fragment extends Fragment implements EditTextDialogFragme (int) (Utils.displayMetrics.heightPixels * 0.8), Utils.displayMetrics.widthPixels); layoutParams.width = ConstraintLayout.LayoutParams.MATCH_PARENT; - layoutParams.height = widthHeight.second; + originalHeight = widthHeight.second; + layoutParams.height = originalHeight; layoutParams.topToBottom = binding.topBarrier.getId(); layoutParams.bottomToTop = bottom.buttonsTopBarrier.getId(); layoutParams.startToStart = ConstraintLayout.LayoutParams.PARENT_ID; layoutParams.endToEnd = ConstraintLayout.LayoutParams.PARENT_ID; - binding.contentRoot.addView(videoPost.getRoot(), 0); + postView = videoPost.getRoot(); + binding.contentRoot.addView(postView, 0); // final GestureDetector gestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() { // @Override @@ -1041,6 +1097,16 @@ public class PostViewV2Fragment extends Fragment implements EditTextDialogFragme if (activity == null) return; Utils.disableKeepScreenOn(activity); } + + @Override + public void onFullScreenModeChanged(final boolean isFullScreen, final StyledPlayerView playerView) { + PostViewV2Fragment.this.playerView = playerView; + if (isFullScreen) { + hideSystemUI(); + return; + } + showSystemUI(); + } }; final float aspectRatio = (float) media.getOriginalWidth() / media.getOriginalHeight(); String videoUrl = null; @@ -1064,92 +1130,6 @@ public class PostViewV2Fragment extends Fragment implements EditTextDialogFragme } } - // private void enablePlayerControls(final boolean enable) { - // video = enable; - // if (enable) { - // binding.playerControlsToggle.setVisibility(View.VISIBLE); - // binding.playerControlsToggle.setOnClickListener(v -> { - // final int visibility = binding.playerControls.getRoot().getVisibility(); - // if (visibility == View.GONE) { - // showPlayerControls(); - // return; - // } - // hidePlayerControls(); - // }); - // return; - // } - // binding.playerControlsToggle.setVisibility(View.GONE); - // hidePlayerControls(); - // } - - // private void hideCaption() { - // if (bottomSheetBehavior == null) return; - // bottomSheetBehavior.setState(BottomSheetBehavior.STATE_HIDDEN); - // } - - // private void showPlayerControls() { - // hideCaption(); - // // previously invisible view - // View view = binding.playerControls.getRoot(); - // if (view.getVisibility() == View.VISIBLE) { - // return; - // } - // if (!ViewCompat.isAttachedToWindow(view)) { - // view.setVisibility(View.VISIBLE); - // return; - // } - // // get the center for the clipping circle - // int cx = view.getWidth() / 2; - // // int cy = view.getHeight() / 2; - // int cy = view.getHeight(); - // - // // get the final radius for the clipping circle - // float finalRadius = (float) Math.hypot(cx, cy); - // - // // create the animator for this view (the start radius is zero) - // Animator anim = ViewAnimationUtils.createCircularReveal(view, cx, cy, 0f, finalRadius); - // - // // make the view visible and start the animation - // view.setVisibility(View.VISIBLE); - // anim.start(); - // - // } - - // private void hidePlayerControls() { - // // previously visible view - // final View view = binding.playerControls.getRoot(); - // if (view.getVisibility() == View.GONE) { - // return; - // } - // if (!ViewCompat.isAttachedToWindow(view)) { - // view.setVisibility(View.GONE); - // return; - // } - // - // // get the center for the clipping circle - // int cx = view.getWidth() / 2; - // // int cy = view.getHeight() / 2; - // int cy = view.getHeight(); - // - // // get the initial radius for the clipping circle - // float initialRadius = (float) Math.hypot(cx, cy); - // - // // create the animation (the final radius is zero) - // Animator anim = ViewAnimationUtils.createCircularReveal(view, cx, cy, initialRadius, 0f); - // - // // make the view invisible when the animation is done - // anim.addListener(new AnimatorListenerAdapter() { - // @Override - // public void onAnimationEnd(Animator animation) { - // super.onAnimationEnd(animation); - // view.setVisibility(View.GONE); - // } - // }); - // - // // start the animation - // anim.start(); - // } - private void setupOptions(final Boolean show) { if (!show) { binding.options.setVisibility(View.GONE); @@ -1282,29 +1262,49 @@ public class PostViewV2Fragment extends Fragment implements EditTextDialogFragme } private void toggleDetails() { - // hasBeenToggled = true; + final boolean hasBeenToggled = true; final Media media = viewModel.getMedia(); binding.getRoot().post(() -> { TransitionManager.beginDelayedTransition(binding.getRoot()); if (detailsVisible) { + final Context context = getContext(); + if (context == null) return; + originalRootBackground = binding.getRoot().getBackground(); + final Resources resources = context.getResources(); + if (resources == null) return; + final ColorDrawable colorDrawable = new ColorDrawable(resources.getColor(R.color.black)); + binding.getRoot().setBackground(colorDrawable); + if (postView != null) { + // Make post match parent + final ViewGroup.LayoutParams layoutParams = postView.getLayoutParams(); + final int fullHeight = Utils.displayMetrics.heightPixels + Utils.getNavigationBarSize(context).y; + layoutParams.height = fullHeight; + binding.contentRoot.getLayoutParams().height = fullHeight; + if (playerView != null) { + playerViewOriginalHeight = playerView.getLayoutParams().height; + playerView.getLayoutParams().height = fullHeight; + } + } detailsVisible = false; if (media.getUser() != null) { binding.profilePic.setVisibility(View.GONE); binding.title.setVisibility(View.GONE); binding.subtitle.setVisibility(View.GONE); - // binding.topBg.setVisibility(View.GONE); } if (media.getLocation() != null) { binding.location.setVisibility(View.GONE); } - // bottom.bottomBg.setVisibility(View.GONE); - // bottom.likesCount.setVisibility(View.GONE); - // bottom.commentsCount.setVisibility(View.GONE); + if (media.getCaption() != null && !TextUtils.isEmpty(media.getCaption().getText())) { + bottom.caption.setVisibility(View.GONE); + bottom.translate.setVisibility(View.GONE); + } + bottom.likesCount.setVisibility(View.GONE); + bottom.commentsCount.setVisibility(View.GONE); bottom.date.setVisibility(View.GONE); bottom.comment.setVisibility(View.GONE); bottom.like.setVisibility(View.GONE); bottom.save.setVisibility(View.GONE); - // bottom.share.setVisibility(View.GONE); + bottom.share.setVisibility(View.GONE); bottom.download.setVisibility(View.GONE); binding.mediaCounter.setVisibility(View.GONE); bottom.viewsCount.setVisibility(View.GONE); @@ -1312,12 +1312,21 @@ public class PostViewV2Fragment extends Fragment implements EditTextDialogFragme if (options != null && !options.isEmpty()) { binding.options.setVisibility(View.GONE); } - // wasControlsVisible = binding.playerControls.getRoot().getVisibility() == View.VISIBLE; - // if (wasControlsVisible) { - // hidePlayerControls(); - // } return; } + if (originalRootBackground != null) { + binding.getRoot().setBackground(originalRootBackground); + } + if (postView != null) { + // Make post height back to original + final ViewGroup.LayoutParams layoutParams = postView.getLayoutParams(); + layoutParams.height = originalHeight; + binding.contentRoot.getLayoutParams().height = ViewGroup.LayoutParams.WRAP_CONTENT; + if (playerView != null) { + playerView.getLayoutParams().height = playerViewOriginalHeight; + playerView = null; + } + } if (media.getUser() != null) { binding.profilePic.setVisibility(View.VISIBLE); binding.title.setVisibility(View.VISIBLE); @@ -1327,17 +1336,20 @@ public class PostViewV2Fragment extends Fragment implements EditTextDialogFragme if (media.getLocation() != null) { binding.location.setVisibility(View.VISIBLE); } - // bottom.bottomBg.setVisibility(View.VISIBLE); + if (media.getCaption() != null && !TextUtils.isEmpty(media.getCaption().getText())) { + bottom.caption.setVisibility(View.VISIBLE); + bottom.translate.setVisibility(View.VISIBLE); + } if (viewModel.hasPk()) { - // bottom.likesCount.setVisibility(View.VISIBLE); + bottom.likesCount.setVisibility(View.VISIBLE); bottom.date.setVisibility(View.VISIBLE); // binding.captionParent.setVisibility(View.VISIBLE); // binding.captionToggle.setVisibility(View.VISIBLE); - // bottom.share.setVisibility(View.VISIBLE); + bottom.share.setVisibility(View.VISIBLE); } if (viewModel.hasPk() && !viewModel.getMedia().isCommentsDisabled()) { bottom.comment.setVisibility(View.VISIBLE); - // bottom.commentsCount.setVisibility(View.VISIBLE); + bottom.commentsCount.setVisibility(View.VISIBLE); } bottom.download.setVisibility(View.VISIBLE); final List options = viewModel.getOptions().getValue(); @@ -1362,6 +1374,64 @@ public class PostViewV2Fragment extends Fragment implements EditTextDialogFragme }); } + private void hideSystemUI() { + if (detailsVisible) { + toggleDetails(); + } + final MainActivity activity = (MainActivity) getActivity(); + if (activity == null) return; + final ActionBar actionBar = activity.getSupportActionBar(); + if (actionBar != null) { + actionBar.hide(); + } + final CollapsingToolbarLayout appbarLayout = activity.getCollapsingToolbarView(); + if (appbarLayout != null) { + appbarLayout.setVisibility(View.GONE); + } + final Toolbar toolbar = activity.getToolbar(); + if (toolbar != null) { + toolbar.setVisibility(View.GONE); + } + final View decorView = activity.getWindow().getDecorView(); + originalSystemUi = decorView.getSystemUiVisibility(); + decorView.setSystemUiVisibility( + View.SYSTEM_UI_FLAG_IMMERSIVE + // Set the content to appear under the system bars so that the + // content doesn't resize when the system bars hide and show. + | View.SYSTEM_UI_FLAG_LAYOUT_STABLE + | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION + | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN + // Hide the nav bar and status bar + | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION + | View.SYSTEM_UI_FLAG_FULLSCREEN); + isInFullScreenMode = true; + } + + // Shows the system bars by removing all the flags + // except for the ones that make the content appear under the system bars. + private void showSystemUI() { + if (!detailsVisible) { + toggleDetails(); + } + final MainActivity activity = (MainActivity) getActivity(); + if (activity == null) return; + final ActionBar actionBar = activity.getSupportActionBar(); + if (actionBar != null) { + actionBar.show(); + } + final CollapsingToolbarLayout appbarLayout = activity.getCollapsingToolbarView(); + if (appbarLayout != null) { + appbarLayout.setVisibility(View.VISIBLE); + } + final Toolbar toolbar = activity.getToolbar(); + if (toolbar != null) { + toolbar.setVisibility(View.VISIBLE); + } + final View decorView = activity.getWindow().getDecorView(); + decorView.setSystemUiVisibility(originalSystemUi); + isInFullScreenMode = false; + } + private void navigateToProfile(final String username) { final NavController navController = getNavController(); if (navController == null) return; diff --git a/app/src/main/java/awais/instagrabber/utils/Utils.java b/app/src/main/java/awais/instagrabber/utils/Utils.java index 9647c2c5..a9424b33 100644 --- a/app/src/main/java/awais/instagrabber/utils/Utils.java +++ b/app/src/main/java/awais/instagrabber/utils/Utils.java @@ -10,6 +10,7 @@ import android.content.Intent; import android.content.res.Resources; import android.content.res.TypedArray; import android.graphics.Color; +import android.graphics.Point; import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.media.MediaScannerConnection; @@ -22,6 +23,7 @@ import android.util.DisplayMetrics; import android.util.Log; import android.util.Pair; import android.util.TypedValue; +import android.view.Display; import android.view.Gravity; import android.view.View; import android.view.Window; @@ -294,6 +296,12 @@ public final class Utils { return outValue.data; } + public static int getAttrResId(@NonNull final Context context, final int attr) { + final TypedValue outValue = new TypedValue(); + context.getTheme().resolveAttribute(attr, outValue, true); + return outValue.resourceId; + } + public static void transparentStatusBar(final Activity activity, final boolean enable, final boolean fullscreen) { @@ -517,4 +525,41 @@ public final class Utils { if (navRootString == null || tabOrderString == null) return false; return tabOrderString.contains(navRootString); } + + @NonNull + public static Point getNavigationBarSize(@NonNull Context context) { + Point appUsableSize = getAppUsableScreenSize(context); + Point realScreenSize = getRealScreenSize(context); + + // navigation bar on the right + if (appUsableSize.x < realScreenSize.x) { + return new Point(realScreenSize.x - appUsableSize.x, appUsableSize.y); + } + + // navigation bar at the bottom + if (appUsableSize.y < realScreenSize.y) { + return new Point(appUsableSize.x, realScreenSize.y - appUsableSize.y); + } + + // navigation bar is not present + return new Point(); + } + + @NonNull + public static Point getAppUsableScreenSize(@NonNull Context context) { + WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); + Display display = windowManager.getDefaultDisplay(); + Point size = new Point(); + display.getSize(size); + return size; + } + + @NonNull + public static Point getRealScreenSize(@NonNull Context context) { + WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); + Display display = windowManager.getDefaultDisplay(); + Point size = new Point(); + display.getRealSize(size); + return size; + } } diff --git a/app/src/main/res/layout/dialog_post_view.xml b/app/src/main/res/layout/dialog_post_view.xml index 76fbbbd2..fa67ecdf 100644 --- a/app/src/main/res/layout/dialog_post_view.xml +++ b/app/src/main/res/layout/dialog_post_view.xml @@ -4,6 +4,7 @@ xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" + android:background="?colorSurface" tools:context=".fragments.PostViewV2Fragment">