package com.kenny.openimgur.fragments;
import android.Manifest;
import android.content.Intent;
import android.graphics.Bitmap;
import android.media.MediaPlayer;
import android.net.Uri;
import android.os.Bundle;
import android.os.Message;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.design.widget.Snackbar;
import android.support.v13.app.FragmentCompat;
import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.TextView;
import com.davemorrissey.labs.subscaleview.ImageSource;
import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView;
import com.kenny.openimgur.R;
import com.kenny.openimgur.classes.ImgurHandler;
import com.kenny.openimgur.classes.ImgurPhoto;
import com.kenny.openimgur.classes.VideoCache;
import com.kenny.openimgur.services.DownloaderService;
import com.kenny.openimgur.ui.VideoView;
import com.kenny.openimgur.util.FileUtil;
import com.kenny.openimgur.util.ImageUtil;
import com.kenny.openimgur.util.LinkUtils;
import com.kenny.openimgur.util.LogUtil;
import com.kenny.openimgur.util.PermissionUtils;
import com.kenny.openimgur.util.RequestCodes;
import com.kenny.openimgur.util.ViewUtils;
import com.kennyc.view.MultiStateView;
import com.nostra13.universalimageloader.core.assist.FailReason;
import com.nostra13.universalimageloader.core.assist.ImageSize;
import com.nostra13.universalimageloader.core.listener.ImageLoadingProgressListener;
import com.nostra13.universalimageloader.core.listener.SimpleImageLoadingListener;
import java.io.File;
import butterknife.BindView;
import pl.droidsonroids.gif.GifDrawable;
/**
* Created by kcampagna on 6/2/15.
*/
public class FullScreenPhotoFragment extends BaseFragment {
private static final String KEY_IMGUR_OBJECT = "imgur_photo_object";
private static final String KEY_VIDEO_POSITION = "position";
private static final long GIF_DELAY = 350L;
@BindView(R.id.image)
SubsamplingScaleImageView imageView;
@BindView(R.id.multiView)
MultiStateView multiView;
@BindView(R.id.video)
VideoView videoView;
@BindView(R.id.gifImage)
ImageView gifImageView;
@BindView(R.id.loadingView)
View loadingView;
@BindView(R.id.fileTransfer)
TextView fileTransfer;
@BindView(R.id.percentage)
TextView percentage;
@BindView(R.id.progressBar)
ProgressBar progressBar;
ImgurPhoto photo;
String url;
boolean startedToLoad = false;
PhotoHandler handler = new PhotoHandler();
boolean replacedPNG = false;
public static FullScreenPhotoFragment createInstance(@NonNull ImgurPhoto photo) {
FullScreenPhotoFragment fragment = new FullScreenPhotoFragment();
Bundle args = new Bundle(1);
args.putParcelable(KEY_IMGUR_OBJECT, photo);
fragment.setArguments(args);
return fragment;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_full_screen, container, false);
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
ViewUtils.setErrorText(multiView, R.id.errorMessage, R.string.error_generic);
((Button) multiView.getView(MultiStateView.VIEW_STATE_ERROR).findViewById(R.id.errorButton)).setText(null);
if (savedInstanceState != null) {
photo = savedInstanceState.getParcelable(KEY_IMGUR_OBJECT);
} else if (getArguments() != null) {
photo = getArguments().getParcelable(KEY_IMGUR_OBJECT);
}
if (photo == null) {
multiView.setViewState(MultiStateView.VIEW_STATE_ERROR);
} else {
configView(savedInstanceState);
}
}
private void configView(Bundle savedInstanceState) {
if (photo.isAnimated()) {
if (photo.isLinkAThumbnail() || photo.getSize() > (1024 * 1024 * 5)) {
url = photo.getVideoLink();
displayVideo(savedInstanceState);
} else {
url = photo.getLink();
if (LinkUtils.isVideoLink(url)) {
displayVideo(savedInstanceState);
} else {
displayImage();
}
}
} else {
url = photo.getLink();
displayImage();
}
}
@Override
public void onDestroyView() {
handler.removeMessages(0);
handler = null;
// Free up some memory
if (gifImageView.getDrawable() instanceof GifDrawable) {
((GifDrawable) gifImageView.getDrawable()).recycle();
} else if (videoView.getDuration() > 0) {
videoView.suspend();
} else {
imageView.recycle();
}
super.onDestroyView();
}
/**
* Displays the image
*/
void displayImage() {
if (!replacedPNG && LinkUtils.isImgurPNG(url)) {
replacedPNG = true;
LogUtil.v(TAG, "Replacing png link with jpeg");
url = url.replace(".png", ".jpeg");
}
ImageUtil.getImageLoader(getActivity()).loadImage(url, new ImageSize(1, 1), ImageUtil.getDisplayOptionsForFullscreen().build(), simpleImageLoadingListener, progressListener);
}
private void displayVideo(Bundle savedInstance) {
File file = VideoCache.getInstance().getVideoFile(url);
final int position;
// Check if our video was playing during a rotation
if (savedInstance != null) {
position = savedInstance.getInt(KEY_VIDEO_POSITION, 0);
} else {
position = 0;
}
if (FileUtil.isFileValid(file)) {
multiView.setViewState(MultiStateView.VIEW_STATE_CONTENT);
videoView.setVisibility(View.VISIBLE);
imageView.setVisibility(View.GONE);
videoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
@Override
public void onPrepared(MediaPlayer mediaPlayer) {
mediaPlayer.setLooping(true);
mediaPlayer.seekTo(position);
}
});
videoView.setVideoPath(file.getAbsolutePath());
if (getUserVisibleHint()) videoView.start();
} else {
VideoCache.getInstance().putVideo(url, new VideoCache.VideoCacheListener() {
@Override
public void onVideoDownloadStart(String key, String url) {
loadingView.setVisibility(View.VISIBLE);
}
@Override
public void onVideoDownloadFailed(Exception ex, String url) {
if (!isAdded() || isRemoving()) return;
multiView.setViewState(MultiStateView.VIEW_STATE_ERROR);
}
@Override
public void onVideoDownloadComplete(File file) {
if (!isAdded() || isRemoving()) return;
multiView.setViewState(MultiStateView.VIEW_STATE_CONTENT);
videoView.setVisibility(View.VISIBLE);
imageView.setVisibility(View.GONE);
videoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
@Override
public void onPrepared(MediaPlayer mediaPlayer) {
mediaPlayer.setLooping(true);
mediaPlayer.seekTo(position);
}
});
videoView.setVideoPath(file.getAbsolutePath());
if (getUserVisibleHint()) videoView.start();
loadingView.setVisibility(View.GONE);
}
@Override
public void onProgress(int downloaded, int total) {
if (!isAdded() || isRemoving()) return;
int progress = (downloaded * 100) / total;
progressBar.setProgress(progress);
percentage.setText(progress + "%");
fileTransfer.setText(FileUtil.humanReadableByteCount(downloaded, false) + "/" + FileUtil.humanReadableByteCount(total, false));
}
});
}
}
void displayGif(String url) {
// Display our gif in a standard image view
if (getUserVisibleHint()) {
// Auto play the gif if we are visible
File file = ImageUtil.getImageLoader(getActivity()).getDiskCache().get(url);
if (!ImageUtil.loadAndDisplayGif(gifImageView, file)) {
multiView.setViewState(MultiStateView.VIEW_STATE_ERROR);
} else {
videoView.setVisibility(View.GONE);
imageView.setVisibility(View.GONE);
multiView.setViewState(MultiStateView.VIEW_STATE_CONTENT);
}
} else {
videoView.setVisibility(View.GONE);
imageView.setVisibility(View.GONE);
ImageUtil.getImageLoader(getActivity()).displayImage(url, gifImageView, null, simpleImageLoadingListener, progressListener);
multiView.setViewState(MultiStateView.VIEW_STATE_CONTENT);
}
}
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
super.onCreateOptionsMenu(menu, inflater);
inflater.inflate(R.menu.view_photo, menu);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.download:
@PermissionUtils.PermissionLevel int permissionLevel = PermissionUtils.getPermissionLevel(this, Manifest.permission.WRITE_EXTERNAL_STORAGE);
switch (permissionLevel) {
case PermissionUtils.PERMISSION_AVAILABLE:
getActivity().startService(DownloaderService.createIntent(getActivity(), url));
break;
case PermissionUtils.PERMISSION_DENIED:
Snackbar.make(multiView, R.string.permission_rationale_download, Snackbar.LENGTH_LONG)
.setAction(R.string.okay, new View.OnClickListener() {
@Override
public void onClick(View v) {
FragmentCompat.requestPermissions(FullScreenPhotoFragment.this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, RequestCodes.REQUEST_PERMISSION_WRITE);
}
}).show();
break;
case PermissionUtils.PERMISSION_NEVER_ASKED:
default:
FragmentCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, RequestCodes.REQUEST_PERMISSION_WRITE);
break;
}
return true;
case R.id.share:
Intent shareIntent = new Intent(Intent.ACTION_SEND);
shareIntent.setType("text/plain");
String link;
if (photo != null && !TextUtils.isEmpty(photo.getTitle())) {
link = photo.getTitle() + " ";
if (TextUtils.isEmpty(photo.getRedditLink())) {
link += photo.getGalleryLink();
} else {
link += String.format("https://reddit.com%s", photo.getRedditLink());
}
} else {
link = url;
}
shareIntent.putExtra(Intent.EXTRA_TEXT, link);
share(shareIntent, R.string.share);
return true;
}
return super.onOptionsItemSelected(item);
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putParcelable(KEY_IMGUR_OBJECT, photo);
if (videoView.isPlaying())
outState.putInt(KEY_VIDEO_POSITION, videoView.getCurrentPosition());
}
@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
if (isVisibleToUser) {
if (gifImageView != null && gifImageView.getDrawable() instanceof GifDrawable) {
((GifDrawable) gifImageView.getDrawable()).start();
} else if (videoView != null && videoView.getDuration() > 0) {
videoView.start();
} else {
handler.sendEmptyMessageDelayed(0, GIF_DELAY);
}
} else {
if (gifImageView != null && gifImageView.getDrawable() instanceof GifDrawable) {
((GifDrawable) gifImageView.getDrawable()).pause();
} else if (videoView != null && videoView.getDuration() > 0) {
videoView.pause();
}
}
}
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch (requestCode) {
case RequestCodes.REQUEST_PERMISSION_WRITE:
boolean granted = PermissionUtils.verifyPermissions(grantResults);
if (granted) {
getActivity().startService(DownloaderService.createIntent(getActivity(), url));
} else {
Snackbar.make(multiView, R.string.permission_denied, Snackbar.LENGTH_LONG).show();
}
break;
}
}
class PhotoHandler extends ImgurHandler {
@Override
public void handleMessage(Message msg) {
if (getUserVisibleHint() && !startedToLoad && gifImageView != null && LinkUtils.isLinkAnimated(url) && !LinkUtils.isVideoLink(url)) {
displayGif(url);
}
super.handleMessage(msg);
}
}
private final ImageLoadingProgressListener progressListener = new ImageLoadingProgressListener() {
@Override
public void onProgressUpdate(String imageUri, View view, int current, int total) {
if (!isAdded() || isRemoving()) return;
int progress = (current * 100) / total;
progressBar.setProgress(progress);
percentage.setText(progress + "%");
fileTransfer.setText(FileUtil.humanReadableByteCount(current, false) + "/" + FileUtil.humanReadableByteCount(total, false));
}
};
private final SimpleImageLoadingListener simpleImageLoadingListener = new SimpleImageLoadingListener() {
@Override
public void onLoadingFailed(String s, View view, FailReason failReason) {
startedToLoad = false;
if (!isAdded() || isRemoving()) return;
if (replacedPNG) {
LogUtil.w(TAG, "Replacing png with jpeg failed, reverting back to png");
url = url.replace(".jpeg", ".png");
displayImage();
return;
}
multiView.setViewState(MultiStateView.VIEW_STATE_ERROR);
}
@Override
public void onLoadingComplete(String url, View view, Bitmap bitmap) {
startedToLoad = false;
bitmap.recycle();
if (!isAdded() || isRemoving()) return;
if (url.endsWith(".gif")) {
displayGif(url);
} else {
// Static images will use the TouchImageView to render the image. This allows large(tall) images to render better and be better legible
try {
File file = ImageUtil.getImageLoader(getActivity()).getDiskCache().get(url);
if (FileUtil.isFileValid(file)) {
// We will enable tiling if any of the image dimensions are above 2048 px (Canvas draw limit)
int[] dimensions = ImageUtil.getBitmapDimensions(file);
boolean enableTiling = dimensions[0] > 2048 || dimensions[1] > 2048;
LogUtil.v(TAG, "Tiling enabled for image " + enableTiling);
Uri fileUri = Uri.fromFile(file);
imageView.setOnImageEventListener(new SubsamplingScaleImageView.OnImageEventListener() {
@Override
public void onReady() {
}
@Override
public void onImageLoaded() {
}
@Override
public void onPreviewLoadError(Exception e) {
}
@Override
public void onImageLoadError(Exception e) {
LogUtil.e(TAG, "Error loading image", e);
if (multiView != null)
multiView.setViewState(MultiStateView.VIEW_STATE_ERROR);
}
@Override
public void onTileLoadError(Exception e) {
LogUtil.e(TAG, "Error creating tile", e);
if (multiView != null)
multiView.setViewState(MultiStateView.VIEW_STATE_ERROR);
}
@Override
public void onPreviewReleased() {
}
});
imageView.setMinimumTileDpi(160);
imageView.setImage(ImageSource.uri(fileUri).dimensions(dimensions[0], dimensions[1]).tiling(enableTiling));
videoView.setVisibility(View.GONE);
gifImageView.setVisibility(View.GONE);
multiView.setViewState(MultiStateView.VIEW_STATE_CONTENT);
} else {
multiView.setViewState(MultiStateView.VIEW_STATE_ERROR);
}
} catch (Exception e) {
LogUtil.e(TAG, "Error creating tile bitmap", e);
multiView.setViewState(MultiStateView.VIEW_STATE_ERROR);
}
}
loadingView.setVisibility(View.GONE);
}
@Override
public void onLoadingStarted(String imageUri, View view) {
startedToLoad = true;
loadingView.setVisibility(View.VISIBLE);
}
};
}