package me.ccrama.redditslide.Activities;
import android.animation.Animator;
import android.animation.ValueAnimator;
import android.app.Activity;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.graphics.PorterDuff;
import android.graphics.drawable.Drawable;
import android.media.MediaScannerConnection;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.support.v4.content.FileProvider;
import android.support.v4.view.animation.FastOutSlowInInterpolator;
import android.support.v7.app.NotificationCompat;
import android.text.Html;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
import com.afollestad.materialdialogs.AlertDialogWrapper;
import com.cocosw.bottomsheet.BottomSheet;
import com.google.common.io.Files;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import com.nostra13.universalimageloader.core.DisplayImageOptions;
import com.nostra13.universalimageloader.core.assist.FailReason;
import com.nostra13.universalimageloader.core.assist.ImageScaleType;
import com.nostra13.universalimageloader.core.imageaware.ImageViewAware;
import com.nostra13.universalimageloader.core.listener.ImageLoadingListener;
import com.nostra13.universalimageloader.core.listener.ImageLoadingProgressListener;
import com.nostra13.universalimageloader.core.listener.SimpleImageLoadingListener;
import org.apache.commons.lang3.StringEscapeUtils;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLConnection;
import java.util.UUID;
import me.ccrama.redditslide.ColorPreferences;
import me.ccrama.redditslide.ContentType;
import me.ccrama.redditslide.Fragments.FolderChooserDialogCreate;
import me.ccrama.redditslide.Fragments.SubmissionsView;
import me.ccrama.redditslide.Notifications.ImageDownloadNotificationService;
import me.ccrama.redditslide.R;
import me.ccrama.redditslide.Reddit;
import me.ccrama.redditslide.SecretConstants;
import me.ccrama.redditslide.SettingValues;
import me.ccrama.redditslide.Views.ImageSource;
import me.ccrama.redditslide.Views.MediaVideoView;
import me.ccrama.redditslide.Views.SubsamplingScaleImageView;
import me.ccrama.redditslide.util.GifUtils;
import me.ccrama.redditslide.util.HttpUtil;
import me.ccrama.redditslide.util.LinkUtil;
import me.ccrama.redditslide.util.LogUtil;
import me.ccrama.redditslide.util.NetworkUtil;
import static me.ccrama.redditslide.Activities.AlbumPager.readableFileSize;
/**
* Created by ccrama on 3/5/2015.
*/
public class MediaView extends FullScreenActivity
implements FolderChooserDialogCreate.FolderCallback {
public static final String EXTRA_URL = "url";
public static final String SUBREDDIT = "sub";
public static final String ADAPTER_POSITION = "adapter_position";
public static final String SUBMISSION_URL = "submission";
public static final String EXTRA_DISPLAY_URL = "displayUrl";
public static final String EXTRA_LQ = "lq";
public static final String EXTRA_SHARE_URL = "urlShare";
public static String fileLoc;
public String subreddit;
public static Runnable doOnClick;
public static boolean didLoadGif;
public float previous;
public boolean hidden;
public boolean imageShown;
public String actuallyLoaded;
public boolean isGif;
private NotificationManager mNotifyManager;
private NotificationCompat.Builder mBuilder;
private int stopPosition;
private GifUtils.AsyncLoadGif gif;
private String contentUrl;
private MediaVideoView videoView;
private Gson gson;
private String mashapeKey;
public static void animateIn(View l) {
l.setVisibility(View.VISIBLE);
ValueAnimator mAnimator = slideAnimator(0, Reddit.dpToPxVertical(56), l);
mAnimator.start();
}
public static void fadeIn(View l) {
ValueAnimator mAnimator = fadeAnimator(0.66f, 1, l);
mAnimator.start();
}
private static ValueAnimator fadeAnimator(float start, float end, final View v) {
ValueAnimator animator = ValueAnimator.ofFloat(start, end);
animator.setInterpolator(new FastOutSlowInInterpolator());
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
//Update Height
float value = (Float) valueAnimator.getAnimatedValue();
v.setAlpha(value);
}
});
return animator;
}
private static ValueAnimator slideAnimator(int start, int end, final View v) {
ValueAnimator animator = ValueAnimator.ofInt(start, end);
animator.setInterpolator(new FastOutSlowInInterpolator());
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
//Update Height
int value = (Integer) valueAnimator.getAnimatedValue();
ViewGroup.LayoutParams layoutParams = v.getLayoutParams();
layoutParams.height = value;
v.setLayoutParams(layoutParams);
}
});
return animator;
}
public static void animateOut(final View l) {
ValueAnimator mAnimator = slideAnimator(Reddit.dpToPxVertical(36), 0, l);
mAnimator.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
}
@Override
public void onAnimationEnd(Animator animation) {
l.setVisibility(View.GONE);
}
@Override
public void onAnimationCancel(Animator animation) {
}
@Override
public void onAnimationRepeat(Animator animation) {
}
});
mAnimator.start();
}
public static void fadeOut(final View l) {
ValueAnimator mAnimator = fadeAnimator(1, .66f, l);
mAnimator.start();
}
public static boolean shouldTruncate(String url) {
try {
final URI uri = new URI(url);
final String path = uri.getPath();
return !ContentType.isGif(uri) && !ContentType.isImage(uri) && path.contains(".");
} catch (URISyntaxException e) {
return false;
}
}
@Override
public void onResume() {
super.onResume();
if (videoView != null) {
videoView.seekTo(stopPosition);
videoView.start();
}
}
public void showBottomSheetImage() {
int[] attrs = new int[]{R.attr.tint};
TypedArray ta = obtainStyledAttributes(attrs);
int color = ta.getColor(0, Color.WHITE);
Drawable external = getResources().getDrawable(R.drawable.openexternal);
Drawable share = getResources().getDrawable(R.drawable.share);
Drawable image = getResources().getDrawable(R.drawable.image);
Drawable save = getResources().getDrawable(R.drawable.save);
Drawable file = getResources().getDrawable(R.drawable.savecontent);
external.setColorFilter(color, PorterDuff.Mode.SRC_ATOP);
share.setColorFilter(color, PorterDuff.Mode.SRC_ATOP);
image.setColorFilter(color, PorterDuff.Mode.SRC_ATOP);
save.setColorFilter(color, PorterDuff.Mode.SRC_ATOP);
file.setColorFilter(color, PorterDuff.Mode.SRC_ATOP);
ta.recycle();
BottomSheet.Builder b = new BottomSheet.Builder(this).title(contentUrl);
b.sheet(2, external, getString(R.string.submission_link_extern));
b.sheet(5, share, getString(R.string.submission_link_share));
if (!isGif) b.sheet(3, image, getString(R.string.share_image));
b.sheet(4, save, "Save " + (isGif ? "MP4" : "image"));
if (isGif
&& !contentUrl.contains(".mp4")
&& !contentUrl.contains("streamable.com")
&& !contentUrl.contains("gfycat.com")
&& !contentUrl.contains("vid.me")) {
String type = contentUrl.substring(contentUrl.lastIndexOf(".") + 1, contentUrl.length())
.toUpperCase();
try {
if (type.equals("GIFV") && new URL(contentUrl).getHost().equals("i.imgur.com")) {
type = "GIF";
contentUrl = contentUrl.replace(".gifv", ".gif");
//todo possibly share gifs b.sheet(9, share, "Share GIF");
}
} catch (MalformedURLException e) {
e.printStackTrace();
}
b.sheet(6, file, getString(R.string.mediaview_save, type));
}
b.listener(new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
switch (which) {
case (2): {
LinkUtil.openExternally(StringEscapeUtils.unescapeHtml4(contentUrl),
MediaView.this, true);
break;
}
case (3): {
shareImage(actuallyLoaded);
break;
}
case (5): {
Reddit.defaultShareText("", StringEscapeUtils.unescapeHtml4(contentUrl),
MediaView.this);
break;
}
case (6): {
saveFile(contentUrl);
}
break;
case (9): {
shareGif(contentUrl);
}
break;
case (4): {
doImageSave();
break;
}
}
}
});
b.show();
}
public void doImageSave() {
if (!isGif) {
if (Reddit.appRestart.getString("imagelocation", "").isEmpty()) {
showFirstDialog();
} else if (!new File(Reddit.appRestart.getString("imagelocation", "")).exists()) {
showErrorDialog();
} else {
Intent i = new Intent(this, ImageDownloadNotificationService.class);
//always download the original file, or use the cached original if that is currently displayed
i.putExtra("actuallyLoaded", contentUrl);
if (subreddit != null && !subreddit.isEmpty()) i.putExtra("subreddit", subreddit);
startService(i);
}
} else {
doOnClick.run();
}
}
public void saveFile(final String baseUrl) {
new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... params) {
if (Reddit.appRestart.getString("imagelocation", "").isEmpty()) {
showFirstDialog();
} else if (!new File(Reddit.appRestart.getString("imagelocation", "")).exists()) {
showErrorDialog();
} else {
final File f = new File(
Reddit.appRestart.getString("imagelocation", "") + File.separator + UUID
.randomUUID()
.toString() + baseUrl.substring(baseUrl.lastIndexOf(".")));
mNotifyManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
mBuilder = new NotificationCompat.Builder(MediaView.this);
mBuilder.setContentTitle(getString(R.string.mediaview_saving, baseUrl))
.setSmallIcon(R.drawable.download_png);
try {
final URL url =
new URL(baseUrl); //wont exist on server yet, just load the full version
URLConnection ucon = url.openConnection();
ucon.setReadTimeout(5000);
ucon.setConnectTimeout(10000);
InputStream is = ucon.getInputStream();
BufferedInputStream inStream = new BufferedInputStream(is, 1024 * 5);
int length = ucon.getContentLength();
f.createNewFile();
FileOutputStream outStream = new FileOutputStream(f);
byte[] buff = new byte[5 * 1024];
int len;
int last = 0;
while ((len = inStream.read(buff)) != -1) {
outStream.write(buff, 0, len);
int percent = Math.round(100.0f * f.length() / length);
if (percent > last) {
last = percent;
mBuilder.setProgress(length, (int) f.length(), false);
mNotifyManager.notify(1, mBuilder.build());
}
}
outStream.flush();
outStream.close();
inStream.close();
MediaScannerConnection.scanFile(MediaView.this,
new String[]{f.getAbsolutePath()}, null,
new MediaScannerConnection.OnScanCompletedListener() {
public void onScanCompleted(String path, Uri uri) {
Intent mediaScanIntent =
new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
Uri contentUri = Uri.parse("file://" + f.getAbsolutePath());
mediaScanIntent.setData(contentUri);
MediaView.this.sendBroadcast(mediaScanIntent);
final Intent shareIntent = new Intent(Intent.ACTION_VIEW);
shareIntent.setDataAndType(contentUri, "image/gif");
PendingIntent contentIntent =
PendingIntent.getActivity(MediaView.this, 0,
shareIntent,
PendingIntent.FLAG_CANCEL_CURRENT);
Notification notif = new NotificationCompat.Builder(
MediaView.this).setContentTitle(
getString(R.string.gif_saved))
.setSmallIcon(R.drawable.save_png)
.setContentIntent(contentIntent)
.build();
NotificationManager mNotificationManager =
(NotificationManager) getSystemService(
Activity.NOTIFICATION_SERVICE);
mNotificationManager.notify(1, notif);
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
return null;
}
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
public void shareGif(final String baseUrl) {
new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... params) {
if (Reddit.appRestart.getString("imagelocation", "").isEmpty()) {
showFirstDialog();
} else if (!new File(Reddit.appRestart.getString("imagelocation", "")).exists()) {
showErrorDialog();
} else {
final File f = new File(
Reddit.appRestart.getString("imagelocation", "") + File.separator + UUID
.randomUUID()
.toString() + baseUrl.substring(baseUrl.lastIndexOf(".")));
mNotifyManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
mBuilder = new NotificationCompat.Builder(MediaView.this);
mBuilder.setContentTitle(getString(R.string.mediaview_saving, baseUrl))
.setSmallIcon(R.drawable.save);
try {
final URL url =
new URL(baseUrl); //wont exist on server yet, just load the full version
URLConnection ucon = url.openConnection();
ucon.setReadTimeout(5000);
ucon.setConnectTimeout(10000);
InputStream is = ucon.getInputStream();
BufferedInputStream inStream = new BufferedInputStream(is, 1024 * 5);
int length = ucon.getContentLength();
f.createNewFile();
FileOutputStream outStream = new FileOutputStream(f);
byte[] buff = new byte[5 * 1024];
int len;
int last = 0;
while ((len = inStream.read(buff)) != -1) {
outStream.write(buff, 0, len);
int percent = Math.round(100.0f * f.length() / length);
if (percent > last) {
last = percent;
mBuilder.setProgress(length, (int) f.length(), false);
mNotifyManager.notify(1, mBuilder.build());
}
}
outStream.flush();
outStream.close();
inStream.close();
MediaScannerConnection.scanFile(MediaView.this,
new String[]{f.getAbsolutePath()}, null,
new MediaScannerConnection.OnScanCompletedListener() {
public void onScanCompleted(String path, Uri uri) {
Intent mediaScanIntent =
new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
Uri contentUri = Uri.parse("file://" + f.getAbsolutePath());
mediaScanIntent.setData(contentUri);
MediaView.this.sendBroadcast(mediaScanIntent);
final Intent shareIntent = new Intent(Intent.ACTION_SEND);
shareIntent.setDataAndType(contentUri, "image/gif");
startActivity(
Intent.createChooser(shareIntent, "Share GIF"));
NotificationManager mNotificationManager =
(NotificationManager) getSystemService(
Activity.NOTIFICATION_SERVICE);
mNotificationManager.cancel(1);
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
return null;
}
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
@Override
public void onDestroy() {
super.onDestroy();
((SubsamplingScaleImageView) findViewById(R.id.submission_image)).recycle();
if (gif != null) gif.cancel(true);
doOnClick = null;
if (!didLoadGif && fileLoc != null && !fileLoc.isEmpty()) {
new File(fileLoc).delete();
}
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
if (videoView != null) {
stopPosition = videoView.getCurrentPosition();
videoView.pause();
outState.putInt("position", stopPosition);
}
}
/* Possible drag to exit implementation in the future
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
if(event.getF) {
// peekView.doScroll(event);
FrameLayout.LayoutParams params =
(FrameLayout.LayoutParams) base.getLayoutParams();
switch (event.getAction()) {
case MotionEvent.ACTION_MOVE:
params.topMargin = (int) -((origY - event.getY()));
if (event.getY() != origY) {
params.leftMargin = twelve *2;
params.rightMargin = twelve * 2;
} else {
params.leftMargin = 0;
params.rightMargin = 0;
}
if (event.getY() != (origY)) {
shouldClose = true;
} else if (event.getY() == (origY)) {
shouldClose = false;
}
base.setLayoutParams(params);
break;
case MotionEvent.ACTION_DOWN:
origY = event.getY();
break;
}
}
// we don't want to pass along the touch event or else it will just scroll under the PeekView}
if (event.getAction() == MotionEvent.ACTION_UP && shouldClose) {
finish();
return false;
}
return super.dispatchTouchEvent(event);
}
*/
public void hideOnLongClick() {
(findViewById(R.id.gifheader)).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (findViewById(R.id.gifheader).getVisibility() == View.GONE) {
animateIn(findViewById(R.id.gifheader));
fadeOut(findViewById(R.id.black));
getWindow().getDecorView().setSystemUiVisibility(0);
} else {
animateOut(findViewById(R.id.gifheader));
fadeIn(findViewById(R.id.black));
getWindow().getDecorView()
.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE);
}
}
});
findViewById(R.id.submission_image).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v2) {
if (findViewById(R.id.gifheader).getVisibility() == View.GONE) {
animateIn(findViewById(R.id.gifheader));
fadeOut(findViewById(R.id.black));
getWindow().getDecorView().setSystemUiVisibility(0);
} else {
finish();
}
}
});
}
@Override
public void onCreate(Bundle savedInstanceState) {
overrideRedditSwipeAnywhere();
super.onCreate(savedInstanceState);
getTheme().applyStyle(new ColorPreferences(this).getDarkThemeSubreddit(""), true);
gson = new Gson();
mashapeKey = SecretConstants.getImgurApiKey(this);
if (savedInstanceState != null && savedInstanceState.containsKey("position")) {
stopPosition = savedInstanceState.getInt("position");
}
doOnClick = new Runnable() {
@Override
public void run() {
}
};
setContentView(R.layout.activity_media);
//Keep the screen on
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
final String firstUrl = getIntent().getExtras().getString(EXTRA_DISPLAY_URL, "");
contentUrl = getIntent().getExtras().getString(EXTRA_URL);
setShareUrl(contentUrl);
if (contentUrl.contains("reddituploads.com")) {
contentUrl = Html.fromHtml(contentUrl).toString();
}
if (contentUrl != null && shouldTruncate(contentUrl)) {
contentUrl = contentUrl.substring(0, contentUrl.lastIndexOf("."));
}
actuallyLoaded = contentUrl;
if (getIntent().hasExtra(SUBMISSION_URL)) {
final int commentUrl = getIntent().getExtras().getInt(ADAPTER_POSITION);
findViewById(R.id.comments).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
finish();
SubmissionsView.datachanged(commentUrl);
}
});
} else {
findViewById(R.id.comments).setVisibility(View.GONE);
}
if (getIntent().hasExtra(SUBREDDIT)) {
subreddit = getIntent().getExtras().getString(SUBREDDIT);
}
if (getIntent().hasExtra(EXTRA_LQ)) {
String lqUrl = getIntent().getStringExtra(EXTRA_DISPLAY_URL);
displayImage(lqUrl);
findViewById(R.id.hq).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
imageShown = false;
doLoad(contentUrl);
findViewById(R.id.hq).setVisibility(View.GONE);
}
});
} else if (ContentType.isImgurImage(contentUrl) && SettingValues.loadImageLq && (
SettingValues.lowResAlways
|| (!NetworkUtil.isConnectedWifi(this) && SettingValues.lowResMobile))) {
String url = contentUrl;
url = url.substring(0, url.lastIndexOf(".")) + (SettingValues.lqLow ? "m"
: (SettingValues.lqMid ? "l" : "h")) + url.substring(url.lastIndexOf("."),
url.length());
displayImage(url);
findViewById(R.id.hq).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
imageShown = false;
doLoad(contentUrl);
findViewById(R.id.hq).setVisibility(View.GONE);
}
});
} else {
if (!firstUrl.isEmpty() && contentUrl != null && ContentType.displayImage(
ContentType.getContentType(contentUrl))) {
((ProgressBar) findViewById(R.id.progress)).setIndeterminate(true);
if (ContentType.isImgurHash(firstUrl)) {
displayImage(firstUrl + ".png");
} else {
displayImage(firstUrl);
}
} else if (firstUrl.isEmpty()) {
imageShown = false;
((ProgressBar) findViewById(R.id.progress)).setIndeterminate(true);
}
findViewById(R.id.hq).setVisibility(View.GONE);
doLoad(contentUrl);
}
if (!Reddit.appRestart.contains("tutorialSwipe")) {
startActivityForResult(new Intent(this, SwipeTutorial.class), 3);
}
findViewById(R.id.more).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
showBottomSheetImage();
}
});
findViewById(R.id.save).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
doImageSave();
}
});
hideOnLongClick();
}
public void doLoad(final String contentUrl) {
switch (ContentType.getContentType(contentUrl)) {
case DEVIANTART:
doLoadDeviantArt(contentUrl);
break;
case IMAGE:
doLoadImage(contentUrl);
break;
case IMGUR:
doLoadImgur(contentUrl);
break;
case XKCD:
doLoadXKCD(contentUrl);
break;
case VID_ME:
case STREAMABLE:
case GIF:
doLoadGif(contentUrl);
break;
}
}
public void doLoadGif(final String dat) {
isGif = true;
findViewById(R.id.hq).setVisibility(View.GONE);
videoView = (MediaVideoView) findViewById(R.id.gif);
findViewById(R.id.black).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (findViewById(R.id.gifheader).getVisibility() == View.GONE) {
animateIn(findViewById(R.id.gifheader));
fadeOut(findViewById(R.id.black));
}
}
});
videoView.clearFocus();
findViewById(R.id.gifarea).setVisibility(View.VISIBLE);
findViewById(R.id.submission_image).setVisibility(View.GONE);
final ProgressBar loader = (ProgressBar) findViewById(R.id.gifprogress);
findViewById(R.id.progress).setVisibility(View.GONE);
gif = new GifUtils.AsyncLoadGif(this, (MediaVideoView) findViewById(R.id.gif), loader,
findViewById(R.id.placeholder), doOnClick, true, false, true,
((TextView) findViewById(R.id.size)), subreddit);
gif.execute(dat);
findViewById(R.id.more).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
showBottomSheetImage();
}
});
}
public void doLoadImgur(String url) {
if (url.endsWith("/")) {
url = url.substring(0, url.length() - 1);
}
final String finalUrl = url;
String hash = url.substring(url.lastIndexOf("/"), url.length());
if (NetworkUtil.isConnected(this)) {
if (hash.startsWith("/")) hash = hash.substring(1, hash.length());
final String apiUrl = "https://imgur-apiv3.p.mashape.com/3/image/" + hash + ".json";
LogUtil.v(apiUrl);
new AsyncTask<Void, Void, JsonObject>() {
@Override
protected JsonObject doInBackground(Void... params) {
return HttpUtil.getImgurMashapeJsonObject(Reddit.client, gson, apiUrl,
mashapeKey);
}
@Override
protected void onPostExecute(JsonObject result) {
if (result != null && !result.isJsonNull() && result.has("error")) {
LogUtil.v("Error loading content");
(MediaView.this).finish();
} else {
try {
if (result != null && !result.isJsonNull() && result.has("image")) {
String type = result.get("image")
.getAsJsonObject()
.get("image")
.getAsJsonObject()
.get("type")
.getAsString();
String urls = result.get("image")
.getAsJsonObject()
.get("links")
.getAsJsonObject()
.get("original")
.getAsString();
if (type.contains("gif")) {
doLoadGif(urls);
} else if (!imageShown) { //only load if there is no image
displayImage(urls);
}
} else if (result != null && result.has("data")) {
String type = result.get("data")
.getAsJsonObject()
.get("type")
.getAsString();
String urls = result.get("data")
.getAsJsonObject()
.get("link")
.getAsString();
String mp4 = "";
if (result.get("data").getAsJsonObject().has("mp4")) {
mp4 = result.get("data")
.getAsJsonObject()
.get("mp4")
.getAsString();
}
if (type.contains("gif")) {
doLoadGif(((mp4 == null || mp4.isEmpty()) ? urls : mp4));
} else if (!imageShown) { //only load if there is no image
displayImage(urls);
}
} else {
if (!imageShown) doLoadImage(finalUrl);
}
} catch (Exception e2) {
e2.printStackTrace();
Intent i = new Intent(MediaView.this, Website.class);
i.putExtra(Website.EXTRA_URL, finalUrl);
MediaView.this.startActivity(i);
finish();
}
}
}
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
}
public void doLoadXKCD(String url) {
if (!url.endsWith("/")) {
url = url + "/";
}
if (NetworkUtil.isConnected(this)) {
final String apiUrl = url + "info.0.json";
LogUtil.v(apiUrl);
final String finalUrl = url;
new AsyncTask<Void, Void, JsonObject>() {
@Override
protected JsonObject doInBackground(Void... params) {
return HttpUtil.getJsonObject(Reddit.client, gson, apiUrl);
}
@Override
protected void onPostExecute(final JsonObject result) {
if (result != null && !result.isJsonNull() && result.has("error")) {
LogUtil.v("Error loading content");
(MediaView.this).finish();
} else {
try {
if (result != null && !result.isJsonNull() && result.has("img")) {
doLoadImage(result.get("img").getAsString());
findViewById(R.id.submission_image).setOnLongClickListener(
new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
try {
new AlertDialogWrapper.Builder(
MediaView.this).setTitle(
result.get("safe_title").getAsString())
.setMessage(
result.get("alt").getAsString())
.show();
} catch (Exception ignored) {
}
return true;
}
});
} else {
Intent i = new Intent(MediaView.this, Website.class);
i.putExtra(Website.EXTRA_URL, finalUrl);
MediaView.this.startActivity(i);
finish();
}
} catch (Exception e2) {
e2.printStackTrace();
Intent i = new Intent(MediaView.this, Website.class);
i.putExtra(Website.EXTRA_URL, finalUrl);
MediaView.this.startActivity(i);
finish();
}
}
}
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
}
public void doLoadDeviantArt(String url) {
final String apiUrl = "http://backend.deviantart.com/oembed?url=" + url;
LogUtil.v(apiUrl);
new AsyncTask<Void, Void, JsonObject>() {
@Override
protected JsonObject doInBackground(Void... params) {
return HttpUtil.getJsonObject(Reddit.client, gson, apiUrl);
}
@Override
protected void onPostExecute(JsonObject result) {
LogUtil.v("doLoad onPostExecute() called with: " + "result = [" + result + "]");
if (result != null && !result.isJsonNull() && (result.has("fullsize_url")
|| result.has("url"))) {
String url;
if (result.has("fullsize_url")) {
url = result.get("fullsize_url").getAsString();
} else {
url = result.get("url").getAsString();
}
doLoadImage(url);
} else {
Intent i = new Intent(MediaView.this, Website.class);
i.putExtra(Website.EXTRA_URL, contentUrl);
MediaView.this.startActivity(i);
finish();
}
}
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
public void doLoadImage(String contentUrl) {
if (contentUrl != null && contentUrl.contains("bildgur.de")) {
contentUrl = contentUrl.replace("b.bildgur.de", "i.imgur.com");
}
if (contentUrl != null && ContentType.isImgurLink(contentUrl)) {
contentUrl = contentUrl + ".png";
}
findViewById(R.id.gifprogress).setVisibility(View.GONE);
if (contentUrl != null && contentUrl.contains("m.imgur.com")) {
contentUrl = contentUrl.replace("m.imgur.com", "i.imgur.com");
}
if (contentUrl == null) {
finish();
//todo maybe something better
}
if ((contentUrl != null
&& !contentUrl.startsWith("https://i.redditmedia.com")
&& !contentUrl.startsWith("https://i.reddituploads.com")
&& !contentUrl.contains(
"imgur.com"))) { //we can assume redditmedia and imgur links are to direct images and not websites
findViewById(R.id.progress).setVisibility(View.VISIBLE);
((ProgressBar) findViewById(R.id.progress)).setIndeterminate(true);
final String finalUrl2 = contentUrl;
new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... params) {
try {
URL obj = new URL(finalUrl2);
URLConnection conn = obj.openConnection();
final String type = conn.getHeaderField("Content-Type");
runOnUiThread(new Runnable() {
@Override
public void run() {
if (!imageShown
&& type != null
&& !type.isEmpty()
&& type.startsWith("image/")) {
//is image
if (type.contains("gif")) {
doLoadGif(finalUrl2.replace(".jpg", ".gif")
.replace(".png", ".gif"));
} else if (!imageShown) {
displayImage(finalUrl2);
}
actuallyLoaded = finalUrl2;
} else if (!imageShown) {
Intent i = new Intent(MediaView.this, Website.class);
i.putExtra(Website.EXTRA_URL, finalUrl2);
MediaView.this.startActivity(i);
finish();
}
}
});
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
@Override
protected void onPostExecute(Void aVoid) {
findViewById(R.id.progress).setVisibility(View.GONE);
}
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
} else {
displayImage(contentUrl);
}
actuallyLoaded = contentUrl;
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == 3) {
Reddit.appRestart.edit().putBoolean("tutorialSwipe", true).apply();
}
}
public void displayImage(final String urlB) {
LogUtil.v("Displaying " + urlB);
final String url = StringEscapeUtils.unescapeHtml4(urlB);
if (!imageShown) {
actuallyLoaded = url;
final SubsamplingScaleImageView i =
(SubsamplingScaleImageView) findViewById(R.id.submission_image);
i.setMinimumDpi(70);
i.setMinimumTileDpi(240);
final ProgressBar bar = (ProgressBar) findViewById(R.id.progress);
bar.setIndeterminate(false);
bar.setProgress(0);
final Handler handler = new Handler();
final Runnable progressBarDelayRunner = new Runnable() {
public void run() {
bar.setVisibility(View.VISIBLE);
}
};
handler.postDelayed(progressBarDelayRunner, 500);
ImageView fakeImage = new ImageView(MediaView.this);
fakeImage.setLayoutParams(new LinearLayout.LayoutParams(i.getWidth(), i.getHeight()));
fakeImage.setScaleType(ImageView.ScaleType.CENTER_CROP);
File f = ((Reddit) getApplicationContext()).getImageLoader().getDiscCache().get(url);
if (f != null && f.exists()) {
imageShown = true;
i.setOnImageEventListener(new SubsamplingScaleImageView.OnImageEventListener() {
@Override
public void onReady() {
}
@Override
public void onImageLoaded() {
}
@Override
public void onPreviewLoadError(Exception e) {
}
@Override
public void onImageLoadError(Exception e) {
imageShown = false;
LogUtil.v("No image displayed");
}
@Override
public void onTileLoadError(Exception e) {
}
});
try {
i.setImage(ImageSource.uri(f.getAbsolutePath()));
} catch (Exception e) {
imageShown = false;
//todo i.setImage(ImageSource.bitmap(loadedImage));
}
(findViewById(R.id.progress)).setVisibility(View.GONE);
handler.removeCallbacks(progressBarDelayRunner);
previous = i.scale;
final float base = i.scale;
i.postDelayed(new Runnable() {
@Override
public void run() {
i.setOnZoomChangedListener(
new SubsamplingScaleImageView.OnZoomChangedListener() {
@Override
public void onZoomLevelChanged(float zoom) {
if (zoom > previous && !hidden && zoom > base) {
hidden = true;
final View base = findViewById(R.id.gifheader);
ValueAnimator va = ValueAnimator.ofFloat(1.0f, 0.2f);
int mDuration = 250; //in millis
va.setDuration(mDuration);
va.addUpdateListener(
new ValueAnimator.AnimatorUpdateListener() {
public void onAnimationUpdate(
ValueAnimator animation) {
Float value =
(Float) animation.getAnimatedValue();
base.setAlpha(value);
}
});
va.start();
//hide
} else if (zoom <= previous && hidden) {
hidden = false;
final View base = findViewById(R.id.gifheader);
ValueAnimator va = ValueAnimator.ofFloat(0.2f, 1.0f);
int mDuration = 250; //in millis
va.setDuration(mDuration);
va.addUpdateListener(
new ValueAnimator.AnimatorUpdateListener() {
public void onAnimationUpdate(
ValueAnimator animation) {
Float value =
(Float) animation.getAnimatedValue();
base.setAlpha(value);
}
});
va.start();
//unhide
}
previous = zoom;
}
});
}
}, 2000);
} else {
final TextView size = (TextView) findViewById(R.id.size);
((Reddit) getApplication()).getImageLoader()
.displayImage(url, new ImageViewAware(fakeImage),
new DisplayImageOptions.Builder().resetViewBeforeLoading(true)
.cacheOnDisk(true)
.imageScaleType(ImageScaleType.NONE)
.cacheInMemory(false)
.build(), new ImageLoadingListener() {
private View mView;
@Override
public void onLoadingStarted(String imageUri, View view) {
imageShown = true;
size.setVisibility(View.VISIBLE);
mView = view;
}
@Override
public void onLoadingFailed(String imageUri, View view,
FailReason failReason) {
Log.v(LogUtil.getTag(), "LOADING FAILED");
imageShown = false;
}
@Override
public void onLoadingComplete(String imageUri, View view,
Bitmap loadedImage) {
imageShown = true;
size.setVisibility(View.GONE);
File f = ((Reddit) getApplicationContext()).getImageLoader()
.getDiscCache()
.get(url);
if (f != null && f.exists()) {
i.setImage(ImageSource.uri(f.getAbsolutePath()));
} else {
i.setImage(ImageSource.bitmap(loadedImage));
}
(findViewById(R.id.progress)).setVisibility(View.GONE);
handler.removeCallbacks(progressBarDelayRunner);
previous = i.scale;
final float base = i.scale;
i.setOnZoomChangedListener(
new SubsamplingScaleImageView.OnZoomChangedListener() {
@Override
public void onZoomLevelChanged(float zoom) {
if (zoom > previous
&& !hidden
&& zoom > base) {
hidden = true;
final View base =
findViewById(R.id.gifheader);
ValueAnimator va =
ValueAnimator.ofFloat(1.0f,
0.2f);
int mDuration = 250; //in millis
va.setDuration(mDuration);
va.addUpdateListener(
new ValueAnimator.AnimatorUpdateListener() {
public void onAnimationUpdate(
ValueAnimator animation) {
Float value =
(Float) animation
.getAnimatedValue();
base.setAlpha(value);
}
});
va.start();
//hide
} else if (zoom <= previous && hidden) {
hidden = false;
final View base =
findViewById(R.id.gifheader);
ValueAnimator va =
ValueAnimator.ofFloat(0.2f,
1.0f);
int mDuration = 250; //in millis
va.setDuration(mDuration);
va.addUpdateListener(
new ValueAnimator.AnimatorUpdateListener() {
public void onAnimationUpdate(
ValueAnimator animation) {
Float value =
(Float) animation
.getAnimatedValue();
base.setAlpha(value);
}
});
va.start();
//unhide
}
previous = zoom;
}
});
}
@Override
public void onLoadingCancelled(String imageUri, View view) {
Log.v(LogUtil.getTag(), "LOADING CANCELLED");
}
}, new ImageLoadingProgressListener() {
@Override
public void onProgressUpdate(String imageUri, View view,
int current, int total) {
size.setText(readableFileSize(total));
((ProgressBar) findViewById(R.id.progress)).setProgress(
Math.round(100.0f * current / total));
}
});
}
}
}
public void showFirstDialog() {
runOnUiThread(new Runnable() {
@Override
public void run() {
try {
new AlertDialogWrapper.Builder(MediaView.this).setTitle(
R.string.set_save_location)
.setMessage(R.string.set_save_location_msg)
.setPositiveButton(R.string.btn_yes,
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
new FolderChooserDialogCreate.Builder(
MediaView.this).chooseButton(
R.string.btn_select) // changes label of the choose button
.initialPath(
Environment.getExternalStorageDirectory()
.getPath()) // changes initial path, defaults to external storage directory
.show();
}
})
.setNegativeButton(R.string.btn_no, null)
.show();
} catch (Exception ignored) {
}
}
});
}
public void showErrorDialog() {
runOnUiThread(new Runnable() {
@Override
public void run() {
new AlertDialogWrapper.Builder(MediaView.this).setTitle(
R.string.err_something_wrong)
.setMessage(R.string.err_couldnt_save_choose_new)
.setPositiveButton(R.string.btn_yes, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
new FolderChooserDialogCreate.Builder(MediaView.this).chooseButton(
R.string.btn_select) // changes label of the choose button
.initialPath(Environment.getExternalStorageDirectory()
.getPath()) // changes initial path, defaults to external storage directory
.show();
}
})
.setNegativeButton(R.string.btn_no, null)
.show();
}
});
}
private void shareImage(final String finalUrl) {
((Reddit) getApplication()).getImageLoader()
.loadImage(finalUrl, new SimpleImageLoadingListener() {
@Override
public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) {
shareImage(loadedImage, finalUrl);
}
});
}
/**
* Converts an image to a PNG, stores it to the cache, then shares it. Saves the image to
* /cache/shared_image for easy deletion. If the /cache/shared_image folder already exists, we
* clear it's contents as to avoid increasing the cache size unnecessarily.
*
* @param bitmap image to share
*/
private void shareImage(final Bitmap bitmap, String original) {
File image; //image to share
//check to see if the cache/shared_images directory is present
final File imagesDir =
new File(this.getCacheDir().toString() + File.separator + "shared_image");
if (!imagesDir.exists()) {
imagesDir.mkdir(); //create the folder if it doesn't exist
} else {
deleteFilesInDir(imagesDir);
}
try {
//creates a file in the cache; filename will be prefixed with "img" and end with ".png"
image = File.createTempFile("img", ".png", imagesDir);
File f = ((Reddit) getApplicationContext()).getImageLoader()
.getDiscCache()
.get(original);
if (f != null) {
try {
Files.copy(f, image);
shareFile(image);
} catch (IOException e) {
doAlternativeImageSave(image, bitmap, original);
shareFile(image);
e.printStackTrace();
}
} else {
doAlternativeImageSave(image, bitmap, original);
shareFile(image);
}
} catch (IOException | NullPointerException e) {
e.printStackTrace();
Toast.makeText(this, getString(R.string.err_share_image), Toast.LENGTH_LONG).show();
}
}
public void shareFile(File image) {
final String authority =
(this.getPackageName()).concat(".").concat(MediaView.class.getSimpleName());
final Uri contentUri = FileProvider.getUriForFile(this, authority, image);
if (contentUri != null) {
final Intent shareImageIntent = new Intent(Intent.ACTION_SEND);
shareImageIntent.addFlags(
Intent.FLAG_GRANT_READ_URI_PERMISSION); //temp permission for receiving app to read this file
shareImageIntent.putExtra(Intent.EXTRA_STREAM, contentUri);
shareImageIntent.setDataAndType(contentUri, getContentResolver().getType(contentUri));
//Select a share option
startActivity(
Intent.createChooser(shareImageIntent, getString(R.string.misc_img_share)));
} else {
Toast.makeText(this, getString(R.string.err_share_image), Toast.LENGTH_LONG).show();
}
}
public void doAlternativeImageSave(File image, Bitmap bitmap, String original)
throws IOException {
FileOutputStream out = null;
try {
//convert image to png
out = new FileOutputStream(image);
bitmap.compress(original.endsWith("png") ? Bitmap.CompressFormat.PNG
: Bitmap.CompressFormat.JPEG, 100, out);
} finally {
if (out != null) {
out.close();
/**
* If a user has both a debug build and a release build installed, the authority name needs to be unique
*/
final String authority =
(this.getPackageName()).concat(".").concat(MediaView.class.getSimpleName());
final Uri contentUri = FileProvider.getUriForFile(this, authority, image);
if (contentUri != null) {
final Intent shareImageIntent = new Intent(Intent.ACTION_SEND);
shareImageIntent.addFlags(
Intent.FLAG_GRANT_READ_URI_PERMISSION); //temp permission for receiving app to read this file
shareImageIntent.putExtra(Intent.EXTRA_STREAM, contentUri);
shareImageIntent.setDataAndType(contentUri,
getContentResolver().getType(contentUri));
//Select a share option
startActivity(Intent.createChooser(shareImageIntent,
getString(R.string.misc_img_share)));
} else {
Toast.makeText(this, getString(R.string.err_share_image), Toast.LENGTH_LONG)
.show();
}
}
}
}
/**
* Deletes all files in a folder
*
* @param dir to clear contents
*/
private void deleteFilesInDir(File dir) {
for (File child : dir.listFiles()) {
child.delete();
}
}
@Override
public void onFolderSelection(FolderChooserDialogCreate dialog, File folder) {
if (folder != null) {
Reddit.appRestart.edit().putString("imagelocation", folder.getAbsolutePath()).apply();
Toast.makeText(this,
getString(R.string.settings_set_image_location, folder.getAbsolutePath()),
Toast.LENGTH_LONG).show();
}
}
}