BarInsta/app/src/main/java/awais/instagrabber/fragments/PostViewV2Fragment.java

1634 lines
70 KiB
Java
Raw Normal View History

2020-10-17 10:07:03 +00:00
package awais.instagrabber.fragments;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
import android.animation.PropertyValuesHolder;
import android.animation.ValueAnimator;
import android.annotation.SuppressLint;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
2020-11-06 22:49:29 +00:00
import android.content.Intent;
2020-10-17 10:07:03 +00:00
import android.content.pm.PackageManager;
import android.graphics.Color;
import android.graphics.drawable.Animatable;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
2020-10-17 10:07:03 +00:00
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.text.SpannableStringBuilder;
import android.text.Spanned;
2020-10-17 10:07:03 +00:00
import android.util.Log;
import android.view.GestureDetector;
2020-10-17 10:07:03 +00:00
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.MotionEvent;
2020-10-17 10:07:03 +00:00
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.view.Window;
import android.view.WindowManager;
import android.widget.FrameLayout;
import android.widget.ScrollView;
2020-11-06 22:49:29 +00:00
import android.widget.Toast;
2020-10-17 10:07:03 +00:00
import android.widget.ViewSwitcher;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.content.res.AppCompatResources;
import androidx.appcompat.view.ContextThemeWrapper;
import androidx.appcompat.widget.PopupMenu;
2020-10-17 10:07:03 +00:00
import androidx.constraintlayout.widget.ConstraintLayout;
import androidx.core.content.PermissionChecker;
import androidx.core.widget.NestedScrollView;
import androidx.fragment.app.DialogFragment;
import androidx.fragment.app.FragmentActivity;
import androidx.lifecycle.LiveData;
2021-01-23 04:33:36 +00:00
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProvider;
2021-01-23 04:33:36 +00:00
import androidx.navigation.NavBackStackEntry;
2020-10-17 10:07:03 +00:00
import androidx.navigation.NavController;
import androidx.navigation.fragment.NavHostFragment;
import androidx.recyclerview.widget.RecyclerView;
import androidx.transition.TransitionManager;
import androidx.viewpager2.widget.ViewPager2;
import com.facebook.drawee.backends.pipeline.Fresco;
import com.facebook.drawee.controller.BaseControllerListener;
import com.facebook.drawee.drawable.ScalingUtils;
import com.facebook.drawee.generic.GenericDraweeHierarchy;
import com.facebook.drawee.interfaces.DraweeController;
import com.facebook.imagepipeline.image.ImageInfo;
import com.facebook.imagepipeline.request.ImageRequest;
import com.facebook.imagepipeline.request.ImageRequestBuilder;
import com.google.android.material.bottomsheet.BottomSheetBehavior;
import com.google.android.material.snackbar.BaseTransientBottomBar;
import com.google.android.material.snackbar.Snackbar;
import java.io.Serializable;
import java.util.List;
2020-10-17 10:07:03 +00:00
import awais.instagrabber.R;
import awais.instagrabber.adapters.SliderCallbackAdapter;
import awais.instagrabber.adapters.SliderItemsAdapter;
import awais.instagrabber.adapters.viewholder.SliderVideoViewHolder;
import awais.instagrabber.customviews.SharedElementTransitionDialogFragment;
import awais.instagrabber.customviews.VerticalImageSpan;
2020-10-17 10:07:03 +00:00
import awais.instagrabber.customviews.VideoPlayerCallbackAdapter;
import awais.instagrabber.customviews.VideoPlayerViewHelper;
import awais.instagrabber.customviews.drawee.AnimatedZoomableController;
import awais.instagrabber.databinding.DialogPostViewBinding;
import awais.instagrabber.dialogs.EditTextDialogFragment;
import awais.instagrabber.models.Resource;
2020-10-17 10:07:03 +00:00
import awais.instagrabber.models.enums.MediaItemType;
import awais.instagrabber.repositories.responses.Caption;
import awais.instagrabber.repositories.responses.Location;
import awais.instagrabber.repositories.responses.Media;
import awais.instagrabber.repositories.responses.User;
import awais.instagrabber.repositories.responses.VideoVersion;
2020-10-17 10:07:03 +00:00
import awais.instagrabber.utils.Constants;
import awais.instagrabber.utils.DownloadUtils;
import awais.instagrabber.utils.NumberUtils;
import awais.instagrabber.utils.ResponseBodyUtils;
2020-10-17 10:07:03 +00:00
import awais.instagrabber.utils.TextUtils;
import awais.instagrabber.utils.Utils;
import awais.instagrabber.viewmodels.PostViewV2ViewModel;
2020-10-17 10:07:03 +00:00
import static androidx.core.content.PermissionChecker.checkSelfPermission;
import static awais.instagrabber.fragments.HashTagFragment.ARG_HASHTAG;
2020-10-17 10:07:03 +00:00
import static awais.instagrabber.utils.DownloadUtils.WRITE_PERMISSION;
import static awais.instagrabber.utils.Utils.settingsHelper;
public class PostViewV2Fragment extends SharedElementTransitionDialogFragment implements EditTextDialogFragment.EditTextDialogFragmentCallback {
2020-10-17 10:07:03 +00:00
private static final String TAG = "PostViewV2Fragment";
private static final int DETAILS_HIDE_DELAY_MILLIS = 2000;
private static final String ARG_MEDIA = "media";
private static final String ARG_SLIDER_POSITION = "position";
2020-10-17 10:07:03 +00:00
private static final int STORAGE_PERM_REQUEST_CODE = 8020;
// private Media media;
2020-10-17 10:07:03 +00:00
private View sharedProfilePicElement;
private View sharedMainPostElement;
private DialogPostViewBinding binding;
// private MediaService mediaService;
2020-10-17 10:07:03 +00:00
private Context context;
private BottomSheetBehavior<NestedScrollView> bottomSheetBehavior;
2021-05-02 18:16:40 +00:00
private boolean detailsVisible = true;
private boolean video;
2020-10-17 10:07:03 +00:00
private VideoPlayerViewHelper videoPlayerViewHelper;
private SliderItemsAdapter sliderItemsAdapter;
2021-05-02 18:16:40 +00:00
// private boolean wasControlsVisible;
2020-10-17 10:07:03 +00:00
private boolean wasPaused;
private int captionState = BottomSheetBehavior.STATE_HIDDEN;
2020-11-03 10:01:59 +00:00
private int sliderPosition = -1;
private DialogInterface.OnShowListener onShowListener;
private boolean hasBeenToggled = false;
private PostViewV2ViewModel viewModel;
private PopupMenu optionsPopup;
private EditTextDialogFragment editTextDialogFragment;
private boolean wasDeleted;
2021-01-23 04:33:36 +00:00
private MutableLiveData<Object> backStackSavedStateResultLiveData;
private OnDeleteListener onDeleteListener;
2021-01-23 04:33:36 +00:00
private final Observer<Object> backStackSavedStateObserver = result -> {
if (result == null) return;
if (result instanceof String) {
final String collection = (String) result;
handleSaveUnsaveResourceLiveData(viewModel.toggleSave(collection, viewModel.getMedia().hasViewerSaved()));
}
// clear result
backStackSavedStateResultLiveData.postValue(null);
};
2021-03-17 11:45:40 +00:00
private final GestureDetector.OnGestureListener videoPlayerViewGestureListener = new GestureDetector.SimpleOnGestureListener() {
@Override
public boolean onSingleTapConfirmed(final MotionEvent e) {
binding.videoPost.playerView.performClick();
return true;
}
};
2021-01-23 04:33:36 +00:00
// private final VerticalDragHelper.OnVerticalDragListener onVerticalDragListener = new VerticalDragHelper.OnVerticalDragListener() {
//
// @Override
// public void onDrag(final float dY) {
// // allow the view to be draggable
// final ConstraintLayout v = binding.getRoot();
// final float finalY = v.getY() + dY;
// animateY(v, finalY, 0, null);
// }
//
// @Override
// public void onDragEnd() {
// // animate and dismiss if user drags the view more that 30% of the view
// if (Math.abs(binding.getRoot().getY()) > Utils.displayMetrics.heightPixels * 0.25) {
// animateAndDismiss(binding.getRoot().getY() < 0 ? 1 : -1);
// return;
// }
// // animate back the view to proper position
// animateY(binding.getRoot(), 0, 200, null);
// }
//
// @Override
// public void onFling(final double flingVelocity) {
// // animate and dismiss if user flings up/down
// animateAndDismiss(flingVelocity > 0 ? 1 : -1);
// }
//
// private void animateAndDismiss(final int direction) {
// final int height = binding.getRoot().getHeight();
// final int finalYDist = height + Utils.getStatusBarHeight(context);
// // less than 0 means up direction, else down
// final int finalY = direction > 0 ? -finalYDist : finalYDist;
// animateY(binding.getRoot(), finalY, 200, new AnimatorListenerAdapter() {
// @Override
// public void onAnimationEnd(final Animator animation) {
// dismiss();
// }
// });
// }
// };
2020-10-17 10:07:03 +00:00
public void setOnShowListener(final DialogInterface.OnShowListener onShowListener) {
this.onShowListener = onShowListener;
}
public void setOnDeleteListener(final OnDeleteListener onDeleteListener) {
if (onDeleteListener == null) return;
this.onDeleteListener = onDeleteListener;
}
public interface OnDeleteListener {
void onDelete();
}
2020-10-17 10:07:03 +00:00
public static class Builder {
private final Media feedModel;
2020-10-17 10:07:03 +00:00
private View profilePicElement;
private View mainPostElement;
private int position;
2020-10-17 10:07:03 +00:00
public Builder setSharedProfilePicElement(final View profilePicElement) {
this.profilePicElement = profilePicElement;
return this;
}
@SuppressWarnings("UnusedReturnValue")
2020-10-17 10:07:03 +00:00
public Builder setSharedMainPostElement(final View mainPostElement) {
this.mainPostElement = mainPostElement;
return this;
}
public Builder setPosition(final int position) {
this.position = position;
return this;
}
2020-10-17 10:07:03 +00:00
public PostViewV2Fragment build() {
return PostViewV2Fragment.newInstance(feedModel, profilePicElement, mainPostElement, position);
2020-10-17 10:07:03 +00:00
}
public Builder(final Media feedModel) {
2020-10-17 10:07:03 +00:00
this.feedModel = feedModel;
}
}
private static PostViewV2Fragment newInstance(final Media feedModel,
final View profilePicElement,
final View mainPostElement,
final int position) {
2020-10-17 10:07:03 +00:00
final PostViewV2Fragment f = new PostViewV2Fragment(profilePicElement, mainPostElement);
final Bundle args = new Bundle();
args.putSerializable(ARG_MEDIA, feedModel);
if (position >= 0) {
args.putInt(ARG_SLIDER_POSITION, position);
}
2020-10-17 10:07:03 +00:00
f.setArguments(args);
return f;
}
public static Builder builder(final Media feedModel) {
2020-10-17 10:07:03 +00:00
return new Builder(feedModel);
}
// default constructor for fragment manager
public PostViewV2Fragment() {}
private PostViewV2Fragment(final View sharedProfilePicElement,
final View sharedMainPostElement) {
this.sharedProfilePicElement = sharedProfilePicElement;
this.sharedMainPostElement = sharedMainPostElement;
}
@Override
public void onCreate(@Nullable final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setStyle(DialogFragment.STYLE_NO_FRAME, R.style.PostViewV2Style);
viewModel = new ViewModelProvider(this).get(PostViewV2ViewModel.class);
captionState = settingsHelper.getBoolean(Constants.SHOW_CAPTIONS) ?
2021-03-17 11:45:40 +00:00
BottomSheetBehavior.STATE_COLLAPSED : BottomSheetBehavior.STATE_HIDDEN;
2020-10-17 10:07:03 +00:00
}
@Nullable
@Override
public View onCreateView(@NonNull final LayoutInflater inflater,
@Nullable final ViewGroup container,
@Nullable final Bundle savedInstanceState) {
binding = DialogPostViewBinding.inflate(inflater, container, false);
final ConstraintLayout root = binding.getRoot();
final ViewTreeObserver.OnPreDrawListener preDrawListener = new ViewTreeObserver.OnPreDrawListener() {
@Override
public boolean onPreDraw() {
root.getViewTreeObserver().removeOnPreDrawListener(this);
return false;
}
};
root.getViewTreeObserver().addOnPreDrawListener(preDrawListener);
return root;
2020-10-17 10:07:03 +00:00
}
@Override
public void onViewCreated(@NonNull final View view, @Nullable final Bundle savedInstanceState) {
init();
}
@Override
public void onAttach(@NonNull final Context context) {
super.onAttach(context);
this.context = context;
}
@Override
public void onStart() {
super.onStart();
final Dialog dialog = getDialog();
if (dialog == null) return;
final Window window = dialog.getWindow();
if (window == null) return;
window.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
window.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
window.setDimAmount(0);
int width = ViewGroup.LayoutParams.MATCH_PARENT;
int height = ViewGroup.LayoutParams.MATCH_PARENT;
window.setLayout(width, height);
if (!wasPaused && (sharedProfilePicElement != null || sharedMainPostElement != null)) {
final ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(
binding.getRoot().getBackground().mutate(),
PropertyValuesHolder.ofInt("alpha", 0, 255)
);
addAnimator(animator);
}
if (onShowListener != null) {
onShowListener.onShow(dialog);
}
2020-10-17 10:07:03 +00:00
}
@Override
public void onPause() {
super.onPause();
wasPaused = true;
if (bottomSheetBehavior != null) {
captionState = bottomSheetBehavior.getState();
}
if (settingsHelper.getBoolean(Constants.PLAY_IN_BACKGROUND)) return;
final Media media = viewModel.getMedia();
if (media == null) return;
switch (media.getMediaType()) {
case MEDIA_TYPE_VIDEO:
if (videoPlayerViewHelper != null) {
videoPlayerViewHelper.pause();
}
return;
case MEDIA_TYPE_SLIDER:
if (sliderItemsAdapter != null) {
pauseSliderPlayer();
}
default:
}
2020-10-17 10:07:03 +00:00
}
2021-01-23 04:33:36 +00:00
@Override
public void onResume() {
super.onResume();
final NavController navController = NavHostFragment.findNavController(this);
final NavBackStackEntry backStackEntry = navController.getCurrentBackStackEntry();
if (backStackEntry != null) {
backStackSavedStateResultLiveData = backStackEntry.getSavedStateHandle().getLiveData("collection");
backStackSavedStateResultLiveData.observe(getViewLifecycleOwner(), backStackSavedStateObserver);
}
}
2020-10-17 10:07:03 +00:00
@Override
public void onDestroyView() {
super.onDestroyView();
final Media media = viewModel.getMedia();
if (media == null) return;
switch (media.getMediaType()) {
2020-10-17 10:07:03 +00:00
case MEDIA_TYPE_VIDEO:
if (videoPlayerViewHelper != null) {
videoPlayerViewHelper.releasePlayer();
}
return;
case MEDIA_TYPE_SLIDER:
if (sliderItemsAdapter != null) {
releaseAllSliderPlayers();
}
default:
}
}
@Override
public void onSaveInstanceState(@NonNull final Bundle outState) {
super.onSaveInstanceState(outState);
final Media media = viewModel.getMedia();
if (media == null) return;
if (media.getMediaType() == MediaItemType.MEDIA_TYPE_SLIDER) {
outState.putInt(ARG_SLIDER_POSITION, sliderPosition);
}
2020-10-17 10:07:03 +00:00
}
@Override
protected void onBeforeSharedElementAnimation(@NonNull final View startView,
@NonNull final View destView,
@NonNull final SharedElementTransitionDialogFragment.ViewBounds viewBounds) {
GenericDraweeHierarchy hierarchy = null;
if (destView == binding.postImage) {
hierarchy = binding.postImage.getHierarchy();
} else if (destView == binding.videoPost.thumbnailParent) {
hierarchy = binding.videoPost.thumbnail.getHierarchy();
}
if (hierarchy != null) {
final ScalingUtils.ScaleType scaleTypeTo = ScalingUtils.ScaleType.FIT_CENTER;
final ScalingUtils.InterpolatingScaleType scaleType = new ScalingUtils.InterpolatingScaleType(
ScalingUtils.ScaleType.CENTER_CROP,
scaleTypeTo,
viewBounds.getStartBounds(),
viewBounds.getDestBounds()
);
hierarchy.setActualImageScaleType(scaleType);
final ValueAnimator animator = ValueAnimator.ofFloat(0, 1);
animator.setDuration(getAnimationDuration());
animator.addUpdateListener(animation -> {
float fraction = (float) animation.getAnimatedValue();
scaleType.setValue(fraction);
});
final GenericDraweeHierarchy finalHierarchy = hierarchy;
animator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
finalHierarchy.setActualImageScaleType(scaleTypeTo);
destView.requestLayout();
}
});
addAnimator(animator);
}
}
@Override
protected void onEndSharedElementAnimation(@NonNull final View startView,
@NonNull final View destView,
@NonNull final ViewBounds viewBounds) {
if (destView == binding.postImage) {
binding.postImage.setTranslationX(0);
binding.postImage.setTranslationY(0);
binding.postImage.setX(0);
binding.postImage.setY(0);
binding.postImage.setLayoutParams(new ConstraintLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT));
binding.postImage.requestLayout();
if (bottomSheetBehavior != null) {
bottomSheetBehavior.setState(captionState);
}
2020-10-17 10:07:03 +00:00
return;
}
if (destView == binding.sliderParent) {
binding.sliderParent.setLayoutParams(new ConstraintLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT));
binding.sliderParent.requestLayout();
2020-11-08 06:48:48 +00:00
if (bottomSheetBehavior != null) {
bottomSheetBehavior.setState(captionState);
2020-11-08 06:48:48 +00:00
}
2020-10-17 10:07:03 +00:00
return;
}
if (destView == binding.videoPost.thumbnailParent) {
final FrameLayout.LayoutParams params = new ViewSwitcher.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT);
params.gravity = Gravity.CENTER;
binding.videoPost.thumbnailParent.setLayoutParams(params);
binding.videoPost.thumbnailParent.requestLayout();
2020-11-08 06:48:48 +00:00
if (bottomSheetBehavior != null) {
bottomSheetBehavior.setState(captionState);
2020-11-08 06:48:48 +00:00
}
2020-10-17 10:07:03 +00:00
}
}
@Override
public void onRequestPermissionsResult(final int requestCode, @NonNull final String[] permissions, @NonNull final int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == STORAGE_PERM_REQUEST_CODE && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
DownloadUtils.showDownloadDialog(context, viewModel.getMedia(), sliderPosition);
2020-10-17 10:07:03 +00:00
}
}
private void init() {
final Bundle arguments = getArguments();
if (arguments == null) {
dismiss();
return;
}
final Serializable feedModelSerializable = arguments.getSerializable(ARG_MEDIA);
if (feedModelSerializable == null) {
Log.e(TAG, "onCreate: feedModelSerializable is null");
dismiss();
return;
}
if (!(feedModelSerializable instanceof Media)) {
dismiss();
return;
}
final Media media = (Media) feedModelSerializable;
if (media.getMediaType() == MediaItemType.MEDIA_TYPE_SLIDER) {
sliderPosition = arguments.getInt(ARG_SLIDER_POSITION, 0);
}
viewModel.setMedia(media);
if (!wasPaused && (sharedProfilePicElement != null || sharedMainPostElement != null)) {
binding.getRoot().getBackground().mutate().setAlpha(0);
}
setProfilePicSharedElement();
setupCaptionBottomSheet();
2020-10-17 10:07:03 +00:00
setupCommonActions();
setObservers();
}
private void setObservers() {
viewModel.getUser().observe(getViewLifecycleOwner(), user -> {
if (user == null) {
binding.userDetailsGroup.setVisibility(View.GONE);
return;
}
binding.userDetailsGroup.setVisibility(View.VISIBLE);
binding.getRoot().post(() -> setupProfilePic(user));
binding.getRoot().post(() -> setupTitles(user));
});
viewModel.getCaption().observe(getViewLifecycleOwner(), caption -> binding.getRoot().post(() -> setupCaption(caption)));
viewModel.getLocation().observe(getViewLifecycleOwner(), location -> binding.getRoot().post(() -> setupLocation(location)));
viewModel.getDate().observe(getViewLifecycleOwner(), date -> binding.getRoot().post(() -> {
if (date == null) {
binding.date.setVisibility(View.GONE);
return;
}
binding.date.setVisibility(View.VISIBLE);
binding.date.setText(date);
}));
2021-01-11 17:52:45 +00:00
viewModel.getLikeCount().observe(getViewLifecycleOwner(), count -> {
final long safeCount = getSafeCount(count);
final String likesString = getResources().getQuantityString(R.plurals.likes_count, (int) safeCount, safeCount);
binding.likesCount.setText(likesString);
});
if (!viewModel.getMedia().isCommentsDisabled()) {
viewModel.getCommentCount().observe(getViewLifecycleOwner(), count -> {
final long safeCount = getSafeCount(count);
final String likesString = getResources().getQuantityString(R.plurals.comments_count, (int) safeCount, safeCount);
2021-01-11 17:52:45 +00:00
binding.commentsCount.setText(likesString);
});
}
viewModel.getViewCount().observe(getViewLifecycleOwner(), count -> {
if (count == null) {
binding.viewsCount.setVisibility(View.GONE);
return;
}
binding.viewsCount.setVisibility(View.VISIBLE);
final long safeCount = getSafeCount(count);
final String viewString = getResources().getQuantityString(R.plurals.views_count, (int) safeCount, safeCount);
binding.viewsCount.setText(viewString);
});
viewModel.getType().observe(getViewLifecycleOwner(), this::setupPostTypeLayout);
viewModel.getLiked().observe(getViewLifecycleOwner(), this::setLikedResources);
viewModel.getSaved().observe(getViewLifecycleOwner(), this::setSavedResources);
viewModel.getOptions().observe(getViewLifecycleOwner(), options -> binding.getRoot().post(() -> {
setupOptions(options != null && !options.isEmpty());
createOptionsPopupMenu();
}));
}
@NonNull
private Long getSafeCount(final Long count) {
Long safeCount = count;
if (count == null) {
safeCount = 0L;
}
return safeCount;
}
private void setupCaptionBottomSheet() {
bottomSheetBehavior = BottomSheetBehavior.from(binding.captionParent);
bottomSheetBehavior.setState(captionState);
bottomSheetBehavior.addBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() {
@Override
public void onStateChanged(@NonNull final View bottomSheet, final int newState) {}
@Override
public void onSlide(@NonNull final View bottomSheet, final float slideOffset) {
binding.captionParent.getBackground().mutate().setAlpha((int) (128 + (128 * (slideOffset < 0 ? 0 : slideOffset))));
}
});
if (sharedProfilePicElement == null || sharedMainPostElement == null) {
binding.getRoot().getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
binding.getRoot().getViewTreeObserver().removeOnGlobalLayoutListener(this);
if (bottomSheetBehavior == null) return;
bottomSheetBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED);
}
});
}
2020-10-17 10:07:03 +00:00
}
private void setupCommonActions() {
setupLike();
setupSave();
setupDownload();
setupComment();
setupShare();
}
private void setupComment() {
2021-01-11 17:52:45 +00:00
if (!viewModel.hasPk() || viewModel.getMedia().isCommentsDisabled()) {
binding.comment.setVisibility(View.GONE);
binding.commentsCount.setVisibility(View.GONE);
return;
}
binding.comment.setVisibility(View.VISIBLE);
binding.comment.setOnClickListener(v -> {
final Media media = viewModel.getMedia();
final User user = media.getUser();
if (user == null) return;
final NavController navController = getNavController();
if (navController == null) return;
final Bundle bundle = new Bundle();
bundle.putString("shortCode", media.getCode());
bundle.putString("postId", media.getPk());
bundle.putLong("postUserId", user.getPk());
try {
navController.navigate(R.id.action_global_commentsViewerFragment, bundle);
} catch (Exception e) {
Log.e(TAG, "setupComment: ", e);
}
});
binding.comment.setOnLongClickListener(v -> {
Utils.displayToastAboveView(context, v, getString(R.string.comment));
return true;
});
2020-10-17 10:07:03 +00:00
}
private void setupDownload() {
binding.download.setOnClickListener(v -> {
if (checkSelfPermission(context, WRITE_PERMISSION) == PermissionChecker.PERMISSION_GRANTED) {
DownloadUtils.showDownloadDialog(context, viewModel.getMedia(), sliderPosition);
2020-10-17 10:07:03 +00:00
return;
}
requestPermissions(DownloadUtils.PERMS, STORAGE_PERM_REQUEST_CODE);
});
binding.download.setOnLongClickListener(v -> {
Utils.displayToastAboveView(context, v, getString(R.string.action_download));
return true;
});
2020-10-17 10:07:03 +00:00
}
private void setupLike() {
2021-01-12 17:39:00 +00:00
final boolean likableMedia = viewModel.hasPk() /*&& viewModel.getMedia().isCommentLikesEnabled()*/;
if (!likableMedia) {
binding.like.setVisibility(View.GONE);
binding.likesCount.setVisibility(View.GONE);
return;
}
if (!viewModel.isLoggedIn()) {
binding.like.setVisibility(View.GONE);
return;
}
2020-10-17 10:07:03 +00:00
binding.like.setOnClickListener(v -> {
v.setEnabled(false);
handleLikeUnlikeResourceLiveData(viewModel.toggleLike());
2020-10-17 10:07:03 +00:00
});
binding.like.setOnLongClickListener(v -> {
2020-12-20 20:52:09 +00:00
final NavController navController = getNavController();
if (navController != null && viewModel.isLoggedIn()) {
2020-12-20 20:52:09 +00:00
final Bundle bundle = new Bundle();
bundle.putString("postId", viewModel.getMedia().getPk());
2020-12-26 18:14:08 +00:00
bundle.putBoolean("isComment", false);
2020-12-20 20:52:09 +00:00
navController.navigate(R.id.action_global_likesViewerFragment, bundle);
return true;
2020-12-22 22:23:48 +00:00
}
return true;
});
2020-10-17 10:07:03 +00:00
}
private void handleLikeUnlikeResourceLiveData(@NonNull final LiveData<Resource<Object>> resource) {
resource.observe(getViewLifecycleOwner(), value -> {
switch (value.status) {
case SUCCESS:
binding.like.setEnabled(true);
break;
case ERROR:
binding.like.setEnabled(true);
unsuccessfulLike();
break;
case LOADING:
binding.like.setEnabled(false);
break;
}
});
}
private void unsuccessfulLike() {
final int errorTextResId;
final Media media = viewModel.getMedia();
if (!media.hasLiked()) {
Log.e(TAG, "like unsuccessful!");
errorTextResId = R.string.like_unsuccessful;
} else {
Log.e(TAG, "unlike unsuccessful!");
errorTextResId = R.string.unlike_unsuccessful;
}
final Snackbar snackbar = Snackbar.make(binding.getRoot(), errorTextResId, BaseTransientBottomBar.LENGTH_INDEFINITE);
snackbar.setAction(R.string.ok, null);
snackbar.show();
}
2020-10-17 10:07:03 +00:00
private void setLikedResources(final boolean liked) {
final int iconResource;
final int tintResource;
if (liked) {
iconResource = R.drawable.ic_like;
tintResource = R.color.red_600;
2020-11-18 16:01:55 +00:00
// textResId = R.string.unlike_without_count;
2020-10-17 10:07:03 +00:00
} else {
iconResource = R.drawable.ic_not_liked;
tintResource = R.color.white;
2020-11-18 16:01:55 +00:00
// textResId = R.string.like_without_count;
2020-10-17 10:07:03 +00:00
}
binding.like.setIconResource(iconResource);
binding.like.setIconTintResource(tintResource);
}
private void setupSave() {
if (!viewModel.isLoggedIn() || !viewModel.hasPk() || !viewModel.getMedia().canViewerSave()) {
binding.save.setVisibility(View.GONE);
return;
}
2020-10-17 10:07:03 +00:00
binding.save.setOnClickListener(v -> {
binding.save.setEnabled(false);
handleSaveUnsaveResourceLiveData(viewModel.toggleSave());
2020-10-17 10:07:03 +00:00
});
binding.save.setOnLongClickListener(v -> {
2021-01-23 04:33:36 +00:00
final NavController navController = NavHostFragment.findNavController(this);
final Bundle bundle = new Bundle();
bundle.putBoolean("isSaving", true);
navController.navigate(R.id.action_global_savedCollectionsFragment, bundle);
return true;
});
2020-10-17 10:07:03 +00:00
}
private void handleSaveUnsaveResourceLiveData(@NonNull final LiveData<Resource<Object>> resource) {
resource.observe(getViewLifecycleOwner(), value -> {
if (value == null) return;
switch (value.status) {
case SUCCESS:
binding.save.setEnabled(true);
break;
case ERROR:
binding.save.setEnabled(true);
unsuccessfulSave();
break;
case LOADING:
binding.save.setEnabled(false);
break;
}
});
}
private void unsuccessfulSave() {
final int errorTextResId;
final Media media = viewModel.getMedia();
if (!media.hasViewerSaved()) {
Log.e(TAG, "save unsuccessful!");
errorTextResId = R.string.save_unsuccessful;
} else {
Log.e(TAG, "save remove unsuccessful!");
errorTextResId = R.string.save_remove_unsuccessful;
}
final Snackbar snackbar = Snackbar.make(binding.getRoot(), errorTextResId, Snackbar.LENGTH_INDEFINITE);
snackbar.setAction(R.string.ok, null);
snackbar.show();
}
2020-10-17 10:07:03 +00:00
private void setSavedResources(final boolean saved) {
final int iconResource;
final int tintResource;
if (saved) {
iconResource = R.drawable.ic_class_24;
tintResource = R.color.blue_700;
2020-11-18 16:01:55 +00:00
// textResId = R.string.saved;
2020-10-17 10:07:03 +00:00
} else {
iconResource = R.drawable.ic_outline_class_24;
tintResource = R.color.white;
2020-11-18 16:01:55 +00:00
// textResId = R.string.save;
2020-10-17 10:07:03 +00:00
}
binding.save.setIconResource(iconResource);
binding.save.setIconTintResource(tintResource);
}
private void setProfilePicSharedElement() {
2020-10-17 10:07:03 +00:00
if (!wasPaused && sharedProfilePicElement != null) {
addSharedElement(sharedProfilePicElement, binding.profilePic);
}
}
private void setupProfilePic(final User user) {
if (user == null) {
binding.profilePic.setImageURI((String) null);
return;
}
final String uri = user.getProfilePicUrl();
2020-10-17 10:07:03 +00:00
final DraweeController controller = Fresco
.newDraweeControllerBuilder()
.setUri(uri)
2020-10-17 10:07:03 +00:00
.setControllerListener(new BaseControllerListener<ImageInfo>() {
@Override
public void onFailure(final String id, final Throwable throwable) {
startPostponedEnterTransition();
}
@Override
public void onFinalImageSet(final String id,
final ImageInfo imageInfo,
final Animatable animatable) {
startPostponedEnterTransition();
}
})
.build();
binding.profilePic.setController(controller);
binding.profilePic.setOnClickListener(v -> navigateToProfile("@" + user.getUsername()));
2020-10-17 10:07:03 +00:00
}
private void setupTitles(final User user) {
if (user == null) {
binding.title.setVisibility(View.GONE);
binding.subtitle.setVisibility(View.GONE);
return;
}
binding.subtitle.setText(user.getFullName());
setUsername(user);
binding.title.setOnClickListener(v -> navigateToProfile("@" + user.getUsername()));
binding.subtitle.setOnClickListener(v -> navigateToProfile("@" + user.getUsername()));
}
private void setUsername(final User user) {
final SpannableStringBuilder sb = new SpannableStringBuilder(user.getUsername());
final int drawableSize = Utils.convertDpToPx(24);
if (user.isVerified()) {
final Drawable verifiedDrawable = AppCompatResources.getDrawable(context, R.drawable.verified);
VerticalImageSpan verifiedSpan = null;
if (verifiedDrawable != null) {
final Drawable drawable = verifiedDrawable.mutate();
drawable.setBounds(0, 0, drawableSize, drawableSize);
verifiedSpan = new VerticalImageSpan(drawable);
}
try {
if (verifiedSpan != null) {
sb.append(" ");
sb.setSpan(verifiedSpan, sb.length() - 1, sb.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}
} catch (Exception e) {
Log.e(TAG, "setUsername: ", e);
}
2020-10-17 10:07:03 +00:00
}
binding.title.setText(sb);
2020-10-17 10:07:03 +00:00
}
private void setupCaption(final Caption caption) {
2021-02-27 23:30:45 +00:00
if (caption == null || TextUtils.isEmpty(caption.getText())) {
binding.caption.setVisibility(View.GONE);
binding.translate.setVisibility(View.GONE);
binding.captionToggle.setVisibility(View.GONE);
return;
}
final String postCaption = caption.getText();
binding.caption.addOnHashtagListener(autoLinkItem -> {
final NavController navController = NavHostFragment.findNavController(this);
final Bundle bundle = new Bundle();
final String originalText = autoLinkItem.getOriginalText().trim();
bundle.putString(ARG_HASHTAG, originalText);
navController.navigate(R.id.action_global_hashTagFragment, bundle);
});
binding.caption.addOnMentionClickListener(autoLinkItem -> {
final String originalText = autoLinkItem.getOriginalText().trim();
navigateToProfile(originalText);
2020-10-17 10:07:03 +00:00
});
binding.caption.addOnEmailClickListener(autoLinkItem -> Utils.openEmailAddress(getContext(), autoLinkItem.getOriginalText().trim()));
binding.caption.addOnURLClickListener(autoLinkItem -> Utils.openURL(getContext(), autoLinkItem.getOriginalText().trim()));
2020-10-17 10:07:03 +00:00
binding.caption.setOnLongClickListener(v -> {
Utils.copyText(context, postCaption);
2020-10-17 10:07:03 +00:00
return true;
});
binding.caption.setText(postCaption);
binding.translate.setOnClickListener(v -> handleTranslateCaptionResource(viewModel.translateCaption()));
2020-10-17 10:07:03 +00:00
binding.captionToggle.setOnClickListener(v -> {
2020-11-08 06:48:48 +00:00
if (bottomSheetBehavior == null) return;
2020-10-17 10:07:03 +00:00
switch (bottomSheetBehavior.getState()) {
case BottomSheetBehavior.STATE_HIDDEN:
binding.captionParent.fullScroll(ScrollView.FOCUS_UP); // reset scroll position
2021-05-02 18:16:40 +00:00
// if (binding.playerControls.getRoot().getVisibility() == View.VISIBLE) {
// hidePlayerControls();
// }
2020-10-17 10:07:03 +00:00
bottomSheetBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED);
return;
case BottomSheetBehavior.STATE_COLLAPSED:
case BottomSheetBehavior.STATE_EXPANDED:
bottomSheetBehavior.setState(BottomSheetBehavior.STATE_HIDDEN);
return;
case BottomSheetBehavior.STATE_DRAGGING:
case BottomSheetBehavior.STATE_HALF_EXPANDED:
case BottomSheetBehavior.STATE_SETTLING:
default:
}
});
binding.captionToggle.setOnLongClickListener(v -> {
Utils.displayToastAboveView(context, v, getString(R.string.caption));
return true;
});
}
private void handleTranslateCaptionResource(@NonNull final LiveData<Resource<String>> data) {
data.observe(getViewLifecycleOwner(), resource -> {
if (resource == null) return;
switch (resource.status) {
case SUCCESS:
binding.translate.setVisibility(View.GONE);
binding.caption.setText(resource.data);
break;
case ERROR:
binding.translate.setEnabled(true);
String message = resource.message;
if (TextUtils.isEmpty(resource.message)) {
message = getString(R.string.downloader_unknown_error);
}
final Snackbar snackbar = Snackbar.make(binding.getRoot(), message, Snackbar.LENGTH_INDEFINITE);
snackbar.setAction(R.string.ok, null);
snackbar.show();
break;
case LOADING:
binding.translate.setEnabled(false);
break;
}
});
}
private void setupLocation(final Location location) {
if (location == null || !detailsVisible) {
binding.location.setVisibility(View.GONE);
return;
2020-10-17 10:07:03 +00:00
}
final String locationName = location.getName();
if (TextUtils.isEmpty(locationName)) return;
binding.location.setText(locationName);
binding.location.setVisibility(View.VISIBLE);
binding.location.setOnClickListener(v -> {
final NavController navController = getNavController();
if (navController == null) return;
final Bundle bundle = new Bundle();
bundle.putLong("locationId", location.getPk());
navController.navigate(R.id.action_global_locationFragment, bundle);
});
}
private void setupShare() {
if (!viewModel.hasPk()) {
binding.share.setVisibility(View.GONE);
return;
}
binding.share.setVisibility(View.VISIBLE);
2020-11-06 22:49:29 +00:00
binding.share.setOnLongClickListener(v -> {
Utils.displayToastAboveView(context, v, getString(R.string.share));
return true;
});
binding.share.setOnClickListener(v -> {
final Media media = viewModel.getMedia();
final User profileModel = media.getUser();
if (profileModel == null) return;
final boolean isPrivate = profileModel.isPrivate();
if (isPrivate) {
// is this necessary?
2020-11-06 22:49:29 +00:00
Toast.makeText(context, R.string.share_private_post, Toast.LENGTH_LONG).show();
}
2020-11-06 22:49:29 +00:00
Intent sharingIntent = new Intent(android.content.Intent.ACTION_SEND);
sharingIntent.setType("text/plain");
sharingIntent.putExtra(android.content.Intent.EXTRA_TEXT, "https://instagram.com/p/" + media.getCode());
2020-11-06 22:49:29 +00:00
startActivity(Intent.createChooser(sharingIntent,
2020-11-08 06:48:48 +00:00
isPrivate ? getString(R.string.share_private_post) : getString(R.string.share_public_post)));
2020-11-06 22:49:29 +00:00
});
2020-10-17 10:07:03 +00:00
}
private void setupPostTypeLayout(final MediaItemType type) {
if (type == null) return;
switch (type) {
2020-10-17 10:07:03 +00:00
case MEDIA_TYPE_IMAGE:
setupPostImage();
break;
case MEDIA_TYPE_SLIDER:
setupSlider();
break;
case MEDIA_TYPE_VIDEO:
setupVideo();
break;
}
}
@SuppressLint("ClickableViewAccessibility")
private void setupPostImage() {
binding.videoPost.root.setVisibility(View.GONE);
binding.sliderParent.setVisibility(View.GONE);
2021-05-02 18:16:40 +00:00
// binding.playerControlsToggle.setVisibility(View.GONE);
// binding.playerControls.getRoot().setVisibility(View.GONE);
2020-10-17 10:07:03 +00:00
binding.mediaCounter.setVisibility(View.GONE);
binding.postImage.setVisibility(View.VISIBLE);
if (!wasPaused && sharedMainPostElement != null) {
binding.postImage.getHierarchy().setActualImageScaleType(ScalingUtils.ScaleType.CENTER_CROP);
addSharedElement(sharedMainPostElement, binding.postImage);
}
final Media media = viewModel.getMedia();
final String imageUrl = ResponseBodyUtils.getImageUrl(media);
if (TextUtils.isEmpty(imageUrl)) {
return;
}
final ImageRequest requestBuilder = ImageRequestBuilder.newBuilderWithSource(Uri.parse(imageUrl))
2020-10-17 10:07:03 +00:00
.setLocalThumbnailPreviewsEnabled(true)
.build();
final DraweeController controller = Fresco
.newDraweeControllerBuilder()
.setLowResImageRequest(ImageRequest.fromUri(ResponseBodyUtils.getThumbUrl(media)))
2020-10-17 10:07:03 +00:00
.setImageRequest(requestBuilder)
.setControllerListener(new BaseControllerListener<ImageInfo>() {
@Override
public void onFailure(final String id, final Throwable throwable) {
startPostponedEnterTransition();
}
@Override
public void onFinalImageSet(final String id,
final ImageInfo imageInfo,
final Animatable animatable) {
startPostponedEnterTransition();
}
})
.build();
binding.postImage.setController(controller);
// binding.postImage.setOnClickListener(v -> toggleDetails());
2020-10-17 10:07:03 +00:00
final AnimatedZoomableController zoomableController = AnimatedZoomableController.newInstance();
zoomableController.setMaxScaleFactor(3f);
zoomableController.setGestureZoomEnabled(true);
zoomableController.setEnabled(true);
2020-10-17 10:07:03 +00:00
binding.postImage.setZoomableController(zoomableController);
binding.postImage.setTapListener(new GestureDetector.SimpleOnGestureListener() {
@Override
public boolean onSingleTapUp(final MotionEvent e) {
toggleDetails();
return true;
}
});
2020-10-17 10:07:03 +00:00
binding.postImage.setAllowTouchInterceptionWhileZoomed(true);
// binding.postImage.setOnVerticalDragListener(onVerticalDragListener);
2020-10-17 10:07:03 +00:00
}
private void setupSlider() {
final Media media = viewModel.getMedia();
2020-10-17 10:07:03 +00:00
binding.postImage.setVisibility(View.GONE);
binding.videoPost.root.setVisibility(View.GONE);
2021-05-02 18:16:40 +00:00
// binding.playerControlsToggle.setVisibility(View.GONE);
// binding.playerControls.getRoot().setVisibility(View.GONE);
2020-10-17 10:07:03 +00:00
binding.sliderParent.setVisibility(View.VISIBLE);
binding.mediaCounter.setVisibility(View.VISIBLE);
2020-11-01 06:02:54 +00:00
if (!wasPaused && sharedMainPostElement != null) {
2020-10-17 10:07:03 +00:00
addSharedElement(sharedMainPostElement, binding.sliderParent);
}
final boolean hasVideo = media.getCarouselMedia()
.stream()
.anyMatch(postChild -> postChild.getMediaType() == MediaItemType.MEDIA_TYPE_VIDEO);
if (hasVideo) {
final View child = binding.sliderParent.getChildAt(0);
if (child instanceof RecyclerView) {
((RecyclerView) child).setItemViewCacheSize(media.getCarouselMedia().size());
((RecyclerView) child).addRecyclerListener(holder -> {
if (holder instanceof SliderVideoViewHolder) {
((SliderVideoViewHolder) holder).releasePlayer();
}
});
}
}
2021-05-02 18:16:40 +00:00
sliderItemsAdapter = new SliderItemsAdapter(null, true, new SliderCallbackAdapter() {
2020-10-17 10:07:03 +00:00
@Override
public void onThumbnailLoaded(final int position) {
if (position != 0) return;
startPostponedEnterTransition();
}
@Override
public void onItemClicked(final int position) {
2020-12-26 18:32:41 +00:00
toggleDetails();
2020-10-17 10:07:03 +00:00
}
@Override
public void onPlayerPlay(final int position) {
final FragmentActivity activity = getActivity();
if (activity == null) return;
Utils.enabledKeepScreenOn(activity);
2021-05-02 18:16:40 +00:00
// if (!detailsVisible || hasBeenToggled) return;
// showPlayerControls();
2020-10-17 10:07:03 +00:00
}
@Override
public void onPlayerPause(final int position) {
final FragmentActivity activity = getActivity();
if (activity == null) return;
Utils.disableKeepScreenOn(activity);
if (detailsVisible || hasBeenToggled) return;
2020-10-17 10:07:03 +00:00
toggleDetails();
}
@Override
public void onPlayerRelease(final int position) {
final FragmentActivity activity = getActivity();
if (activity == null) return;
Utils.disableKeepScreenOn(activity);
}
2020-10-17 10:07:03 +00:00
});
binding.sliderParent.setAdapter(sliderItemsAdapter);
if (sliderPosition >= 0 && sliderPosition < media.getCarouselMedia().size()) {
binding.sliderParent.setCurrentItem(sliderPosition);
}
2020-10-17 10:07:03 +00:00
binding.sliderParent.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() {
int prevPosition = -1;
@Override
public void onPageScrolled(final int position, final float positionOffset, final int positionOffsetPixels) {
if (prevPosition != -1) {
final View view = binding.sliderParent.getChildAt(0);
if (view instanceof RecyclerView) {
pausePlayerAtPosition(prevPosition, (RecyclerView) view);
pausePlayerAtPosition(position, (RecyclerView) view);
}
}
if (positionOffset == 0) {
prevPosition = position;
}
}
@Override
public void onPageSelected(final int position) {
final int size = media.getCarouselMedia().size();
2020-10-17 10:07:03 +00:00
if (position < 0 || position >= size) return;
sliderPosition = position;
2020-10-17 10:07:03 +00:00
final String text = (position + 1) + "/" + size;
binding.mediaCounter.setText(text);
final Media childMedia = media.getCarouselMedia().get(position);
final View view = binding.sliderParent.getChildAt(0);
2021-05-02 18:16:40 +00:00
// if (prevPosition != -1) {
// if (view instanceof RecyclerView) {
// final RecyclerView.ViewHolder viewHolder = ((RecyclerView) view).findViewHolderForAdapterPosition(prevPosition);
// if (viewHolder instanceof SliderVideoViewHolder) {
// ((SliderVideoViewHolder) viewHolder).removeCallbacks();
// }
// }
// }
video = false;
if (childMedia.getMediaType() == MediaItemType.MEDIA_TYPE_VIDEO) {
2021-05-02 18:16:40 +00:00
// if (view instanceof RecyclerView) {
// final RecyclerView.ViewHolder viewHolder = ((RecyclerView) view).findViewHolderForAdapterPosition(position);
// if (viewHolder instanceof SliderVideoViewHolder) {
// ((SliderVideoViewHolder) viewHolder).resetPlayerTimeline();
// }
// }
// enablePlayerControls(true);
video = true;
viewModel.setViewCount(childMedia.getViewCount());
2020-10-17 10:07:03 +00:00
return;
}
viewModel.setViewCount(null);
2021-05-02 18:16:40 +00:00
// enablePlayerControls(false);
2020-10-17 10:07:03 +00:00
}
private void pausePlayerAtPosition(final int position, final RecyclerView view) {
final RecyclerView.ViewHolder viewHolder = view.findViewHolderForAdapterPosition(position);
if (viewHolder instanceof SliderVideoViewHolder) {
((SliderVideoViewHolder) viewHolder).pause();
}
}
});
final String text = "1/" + media.getCarouselMedia().size();
2020-10-17 10:07:03 +00:00
binding.mediaCounter.setText(text);
sliderItemsAdapter.submitList(media.getCarouselMedia());
2020-10-17 10:07:03 +00:00
}
private void pauseSliderPlayer() {
if (binding.sliderParent.getVisibility() != View.VISIBLE) return;
final int currentItem = binding.sliderParent.getCurrentItem();
final View view = binding.sliderParent.getChildAt(0);
if (!(view instanceof RecyclerView)) return;
final RecyclerView.ViewHolder viewHolder = ((RecyclerView) view).findViewHolderForAdapterPosition(currentItem);
if (!(viewHolder instanceof SliderVideoViewHolder)) return;
((SliderVideoViewHolder) viewHolder).pause();
}
2020-10-17 10:07:03 +00:00
private void releaseAllSliderPlayers() {
if (binding.sliderParent.getVisibility() != View.VISIBLE) return;
final View view = binding.sliderParent.getChildAt(0);
if (!(view instanceof RecyclerView)) return;
final int itemCount = sliderItemsAdapter.getItemCount();
for (int position = itemCount - 1; position >= 0; position--) {
final RecyclerView.ViewHolder viewHolder = ((RecyclerView) view).findViewHolderForAdapterPosition(position);
if (!(viewHolder instanceof SliderVideoViewHolder)) continue;
((SliderVideoViewHolder) viewHolder).releasePlayer();
}
}
@SuppressLint("ClickableViewAccessibility")
private void setupVideo() {
2021-05-02 18:16:40 +00:00
video = true;
final Media media = viewModel.getMedia();
2020-10-17 10:07:03 +00:00
binding.postImage.setVisibility(View.GONE);
binding.sliderParent.setVisibility(View.GONE);
binding.mediaCounter.setVisibility(View.GONE);
// binding.playerControls.getRoot().setVisibility(View.VISIBLE);
2020-11-01 06:02:54 +00:00
if (!wasPaused && sharedMainPostElement != null) {
2020-10-17 10:07:03 +00:00
final GenericDraweeHierarchy hierarchy = binding.videoPost.thumbnail.getHierarchy();
hierarchy.setActualImageScaleType(ScalingUtils.ScaleType.CENTER_CROP);
addSharedElement(sharedMainPostElement, binding.videoPost.thumbnailParent);
}
binding.videoPost.root.setVisibility(View.VISIBLE);
2021-03-17 11:45:40 +00:00
// final VerticalDragHelper thumbnailVerticalDragHelper = new VerticalDragHelper(binding.videoPost.thumbnailParent);
// final VerticalDragHelper playerVerticalDragHelper = new VerticalDragHelper(binding.videoPost.playerView);
// thumbnailVerticalDragHelper.setOnVerticalDragListener(onVerticalDragListener);
// playerVerticalDragHelper.setOnVerticalDragListener(onVerticalDragListener);
2021-05-02 18:16:40 +00:00
// enablePlayerControls(true);
2021-03-17 11:45:40 +00:00
// binding.videoPost.thumbnailParent.setOnTouchListener((v, event) -> {
// final boolean onDragTouch = thumbnailVerticalDragHelper.onDragTouch(event);
// if (onDragTouch) {
// return true;
// }
// return thumbnailVerticalDragHelper.onGestureTouchEvent(event);
// });
// binding.videoPost.playerView.setOnTouchListener((v, event) -> {
// final boolean onDragTouch = playerVerticalDragHelper.onDragTouch(event);
// if (onDragTouch) {
// return true;
// }
// return playerVerticalDragHelper.onGestureTouchEvent(event);
// });
binding.videoPost.playerView.setOnClickListener(v -> toggleDetails());
final GestureDetector gestureDetector = new GestureDetector(context, videoPlayerViewGestureListener);
2020-10-17 10:07:03 +00:00
binding.videoPost.playerView.setOnTouchListener((v, event) -> {
2021-03-17 11:45:40 +00:00
gestureDetector.onTouchEvent(event);
return true;
2020-10-17 10:07:03 +00:00
});
final float vol = settingsHelper.getBoolean(Constants.MUTED_VIDEOS) ? 0f : 1f;
final VideoPlayerViewHelper.VideoPlayerCallback videoPlayerCallback = new VideoPlayerCallbackAdapter() {
@Override
public void onThumbnailLoaded() {
startPostponedEnterTransition();
}
@Override
public void onPlayerViewLoaded() {
// binding.playerControls.getRoot().setVisibility(View.VISIBLE);
2020-10-17 10:07:03 +00:00
final ViewGroup.LayoutParams layoutParams = binding.videoPost.playerView.getLayoutParams();
final int requiredWidth = Utils.displayMetrics.widthPixels;
final int resultingHeight = NumberUtils
.getResultingHeight(requiredWidth, media.getOriginalHeight(), media.getOriginalWidth());
2020-10-17 10:07:03 +00:00
layoutParams.width = requiredWidth;
layoutParams.height = resultingHeight;
binding.videoPost.playerView.requestLayout();
}
@Override
public void onPlay() {
final FragmentActivity activity = getActivity();
if (activity == null) return;
Utils.enabledKeepScreenOn(activity);
2020-10-17 10:07:03 +00:00
if (detailsVisible) {
new Handler().postDelayed(() -> toggleDetails(), DETAILS_HIDE_DELAY_MILLIS);
}
}
@Override
public void onPause() {
final FragmentActivity activity = getActivity();
if (activity == null) return;
Utils.disableKeepScreenOn(activity);
}
@Override
public void onRelease() {
final FragmentActivity activity = getActivity();
if (activity == null) return;
Utils.disableKeepScreenOn(activity);
}
2020-10-17 10:07:03 +00:00
};
final float aspectRatio = (float) media.getOriginalWidth() / media.getOriginalHeight();
String videoUrl = null;
final List<VideoVersion> videoVersions = media.getVideoVersions();
if (videoVersions != null && !videoVersions.isEmpty()) {
final VideoVersion videoVersion = videoVersions.get(0);
if (videoVersion != null) {
videoUrl = videoVersion.getUrl();
}
}
2021-01-08 13:27:52 +00:00
if (videoUrl != null) {
videoPlayerViewHelper = new VideoPlayerViewHelper(
binding.getRoot().getContext(),
binding.videoPost,
videoUrl,
vol,
aspectRatio,
ResponseBodyUtils.getThumbUrl(media),
2021-01-08 13:27:52 +00:00
true,
2021-05-02 18:16:40 +00:00
// /*binding.playerControls*/null,
2021-01-08 13:27:52 +00:00
videoPlayerCallback);
}
2020-10-17 10:07:03 +00:00
}
2021-05-02 18:16:40 +00:00
// 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();
// }
2020-10-17 10:07:03 +00:00
private void hideCaption() {
if (bottomSheetBehavior == null) return;
bottomSheetBehavior.setState(BottomSheetBehavior.STATE_HIDDEN);
}
2021-05-02 18:16:40 +00:00
// 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();
//
// }
2020-10-17 10:07:03 +00:00
2021-05-02 18:16:40 +00:00
// 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();
// }
2020-10-17 10:07:03 +00:00
private void setupOptions(final Boolean show) {
if (!show) {
binding.options.setVisibility(View.GONE);
return;
}
binding.options.setVisibility(View.VISIBLE);
binding.options.setOnClickListener(v -> {
if (optionsPopup == null) return;
optionsPopup.show();
});
}
private void createOptionsPopupMenu() {
if (optionsPopup == null) {
final ContextThemeWrapper themeWrapper = new ContextThemeWrapper(context, R.style.popupMenuStyle);
optionsPopup = new PopupMenu(themeWrapper, binding.options);
} else {
optionsPopup.getMenu().clear();
}
optionsPopup.getMenuInflater().inflate(R.menu.post_view_menu, optionsPopup.getMenu());
// final Menu menu = optionsPopup.getMenu();
// final int size = menu.size();
// for (int i = 0; i < size; i++) {
// final MenuItem item = menu.getItem(i);
// if (item == null) continue;
// if (options.contains(item.getItemId())) continue;
// menu.removeItem(item.getItemId());
// }
optionsPopup.setOnMenuItemClickListener(item -> {
int itemId = item.getItemId();
if (itemId == R.id.edit_caption) {
showCaptionEditDialog();
return true;
}
if (itemId == R.id.delete) {
item.setEnabled(false);
final LiveData<Resource<Object>> resourceLiveData = viewModel.delete();
handleDeleteResource(resourceLiveData, item);
}
return true;
});
}
private void handleDeleteResource(final LiveData<Resource<Object>> resourceLiveData, final MenuItem item) {
if (resourceLiveData == null) return;
resourceLiveData.observe(getViewLifecycleOwner(), new Observer<Resource<Object>>() {
@Override
public void onChanged(final Resource<Object> resource) {
try {
switch (resource.status) {
case SUCCESS:
wasDeleted = true;
if (onDeleteListener != null) {
onDeleteListener.onDelete();
}
break;
case ERROR:
if (item != null) {
item.setEnabled(true);
}
final Snackbar snackbar = Snackbar.make(binding.getRoot(),
R.string.delete_unsuccessful,
Snackbar.LENGTH_INDEFINITE);
snackbar.setAction(R.string.ok, null);
snackbar.show();
break;
case LOADING:
if (item != null) {
item.setEnabled(false);
}
break;
}
} finally {
resourceLiveData.removeObserver(this);
}
}
});
}
private void showCaptionEditDialog() {
final Caption caption = viewModel.getCaption().getValue();
final String captionText = caption != null ? caption.getText() : null;
editTextDialogFragment = EditTextDialogFragment
.newInstance(R.string.edit_caption, R.string.confirm, R.string.cancel, captionText);
editTextDialogFragment.show(getChildFragmentManager(), "edit_caption");
}
@Override
public void onPositiveButtonClicked(final String caption) {
handleEditCaptionResource(viewModel.updateCaption(caption));
if (editTextDialogFragment == null) return;
editTextDialogFragment.dismiss();
editTextDialogFragment = null;
}
private void handleEditCaptionResource(final LiveData<Resource<Object>> updateCaption) {
if (updateCaption == null) return;
updateCaption.observe(getViewLifecycleOwner(), resource -> {
final MenuItem item = optionsPopup.getMenu().findItem(R.id.edit_caption);
switch (resource.status) {
case SUCCESS:
if (item != null) {
item.setEnabled(true);
}
break;
case ERROR:
if (item != null) {
item.setEnabled(true);
}
final Snackbar snackbar = Snackbar.make(binding.getRoot(), R.string.edit_unsuccessful, BaseTransientBottomBar.LENGTH_INDEFINITE);
snackbar.setAction(R.string.ok, null);
snackbar.show();
break;
case LOADING:
if (item != null) {
item.setEnabled(false);
}
break;
}
});
}
@Override
public void onNegativeButtonClicked() {
if (editTextDialogFragment == null) return;
editTextDialogFragment.dismiss();
editTextDialogFragment = null;
}
2020-10-17 10:07:03 +00:00
private void toggleDetails() {
hasBeenToggled = true;
final Media media = viewModel.getMedia();
2020-10-17 10:07:03 +00:00
binding.getRoot().post(() -> {
TransitionManager.beginDelayedTransition(binding.getRoot());
if (detailsVisible) {
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);
2020-10-17 10:07:03 +00:00
}
binding.captionParent.setVisibility(View.GONE);
binding.bottomBg.setVisibility(View.GONE);
binding.likesCount.setVisibility(View.GONE);
binding.commentsCount.setVisibility(View.GONE);
binding.date.setVisibility(View.GONE);
binding.comment.setVisibility(View.GONE);
2020-10-17 10:07:03 +00:00
binding.captionToggle.setVisibility(View.GONE);
2021-05-02 18:16:40 +00:00
// binding.playerControlsToggle.setVisibility(View.GONE);
2020-10-17 10:07:03 +00:00
binding.like.setVisibility(View.GONE);
binding.save.setVisibility(View.GONE);
2020-11-06 22:49:29 +00:00
binding.share.setVisibility(View.GONE);
2020-10-17 10:07:03 +00:00
binding.download.setVisibility(View.GONE);
binding.mediaCounter.setVisibility(View.GONE);
2021-03-17 11:45:40 +00:00
binding.viewsCount.setVisibility(View.GONE);
final List<Integer> options = viewModel.getOptions().getValue();
if (options != null && !options.isEmpty()) {
binding.options.setVisibility(View.GONE);
}
2021-05-02 18:16:40 +00:00
// wasControlsVisible = binding.playerControls.getRoot().getVisibility() == View.VISIBLE;
// if (wasControlsVisible) {
// hidePlayerControls();
// }
2020-10-17 10:07:03 +00:00
return;
}
if (media.getUser() != null) {
binding.profilePic.setVisibility(View.VISIBLE);
binding.title.setVisibility(View.VISIBLE);
binding.subtitle.setVisibility(View.VISIBLE);
binding.topBg.setVisibility(View.VISIBLE);
}
if (media.getLocation() != null) {
binding.location.setVisibility(View.VISIBLE);
2020-10-17 10:07:03 +00:00
}
binding.bottomBg.setVisibility(View.VISIBLE);
2021-01-12 17:39:00 +00:00
if (viewModel.hasPk()) {
binding.likesCount.setVisibility(View.VISIBLE);
binding.date.setVisibility(View.VISIBLE);
binding.captionParent.setVisibility(View.VISIBLE);
binding.captionToggle.setVisibility(View.VISIBLE);
binding.share.setVisibility(View.VISIBLE);
}
if (viewModel.hasPk() && !viewModel.getMedia().isCommentsDisabled()) {
binding.comment.setVisibility(View.VISIBLE);
binding.commentsCount.setVisibility(View.VISIBLE);
}
binding.download.setVisibility(View.VISIBLE);
final List<Integer> options = viewModel.getOptions().getValue();
if (options != null && !options.isEmpty()) {
binding.options.setVisibility(View.VISIBLE);
}
2021-01-12 17:39:00 +00:00
if (viewModel.isLoggedIn() && viewModel.hasPk()) {
binding.like.setVisibility(View.VISIBLE);
binding.save.setVisibility(View.VISIBLE);
}
if (video) {
2021-05-02 18:16:40 +00:00
// binding.playerControlsToggle.setVisibility(View.VISIBLE);
2021-03-17 11:45:40 +00:00
binding.viewsCount.setVisibility(View.VISIBLE);
}
2021-05-02 18:16:40 +00:00
// if (wasControlsVisible) {
// showPlayerControls();
// }
if (media.getMediaType() == MediaItemType.MEDIA_TYPE_SLIDER) {
2020-10-17 10:07:03 +00:00
binding.mediaCounter.setVisibility(View.VISIBLE);
}
detailsVisible = true;
});
}
// private void animateY(final View v,
// final float finalY,
// final int duration,
// final AnimatorListenerAdapter listener) {
// v.animate()
// .y(finalY)
// .setDuration(duration)
// .setListener(listener).start();
// }
2020-10-17 10:07:03 +00:00
private void navigateToProfile(final String username) {
final NavController navController = getNavController();
if (navController == null) return;
final Bundle bundle = new Bundle();
bundle.putString("username", username);
navController.navigate(R.id.action_global_profileFragment, bundle);
}
@Nullable
private NavController getNavController() {
NavController navController = null;
try {
navController = NavHostFragment.findNavController(this);
} catch (IllegalStateException e) {
Log.e(TAG, "navigateToProfile", e);
}
return navController;
}
public boolean wasDeleted() {
return wasDeleted;
}
2020-10-17 10:07:03 +00:00
}