fedilab-Android-App/app/src/main/java/fr/gouv/etalab/mastodon/activities/MediaActivity.java

532 lines
23 KiB
Java
Raw Normal View History

/* Copyright 2017 Thomas Schneider
*
2017-07-10 10:33:24 +02:00
* This file is a part of Mastalab
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
* License, or (at your option) any later version.
*
2017-07-10 10:33:24 +02:00
* Mastalab is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
2017-08-04 11:11:27 +02:00
* You should have received a copy of the GNU General Public License along with Mastalab; if not,
* see <http://www.gnu.org/licenses>. */
package fr.gouv.etalab.mastodon.activities;
import android.Manifest;
2017-08-26 10:57:08 +02:00
import android.annotation.SuppressLint;
2017-06-30 17:09:07 +02:00
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.RectF;
import android.media.MediaPlayer;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
2017-12-02 11:02:25 +01:00
import android.support.annotation.Nullable;
2017-12-22 16:48:37 +01:00
import android.support.design.widget.AppBarLayout;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.ActionBar;
2017-11-07 11:09:09 +01:00
import android.support.v7.widget.Toolbar;
import android.view.GestureDetector;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
2017-11-07 11:09:09 +01:00
import android.view.ViewGroup;
import android.webkit.URLUtil;
import android.widget.ImageView;
import android.widget.MediaController;
2017-12-23 19:31:12 +01:00
import android.widget.ProgressBar;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.VideoView;
2017-12-02 11:02:25 +01:00
import com.bumptech.glide.Glide;
import com.bumptech.glide.load.DataSource;
import com.bumptech.glide.load.engine.GlideException;
import com.bumptech.glide.request.RequestListener;
import com.bumptech.glide.request.target.SimpleTarget;
import com.bumptech.glide.request.target.Target;
import com.bumptech.glide.request.transition.Transition;
import com.github.chrisbanes.photoview.OnMatrixChangedListener;
import com.github.chrisbanes.photoview.PhotoView;
import java.io.File;
import java.util.ArrayList;
2017-12-23 19:31:12 +01:00
import fr.gouv.etalab.mastodon.R;
import fr.gouv.etalab.mastodon.client.Entities.Attachment;
2017-11-18 12:22:41 +01:00
import fr.gouv.etalab.mastodon.client.Entities.Error;
import fr.gouv.etalab.mastodon.client.HttpsConnection;
import fr.gouv.etalab.mastodon.helper.Helper;
2017-11-18 12:22:41 +01:00
import fr.gouv.etalab.mastodon.interfaces.OnDownloadInterface;
import static fr.gouv.etalab.mastodon.helper.Helper.EXTERNAL_STORAGE_REQUEST_CODE;
2017-07-10 09:24:58 +02:00
import static fr.gouv.etalab.mastodon.helper.Helper.changeDrawableColor;
/**
* Created by Thomas on 25/06/2017.
* Media Activity
*/
2017-12-12 18:17:01 +01:00
public class MediaActivity extends BaseActivity implements OnDownloadInterface {
private RelativeLayout loader;
private ArrayList<Attachment> attachments;
private PhotoView imageView;
private VideoView videoView;
2017-07-10 09:24:58 +02:00
private float downX;
private int mediaPosition;
MediaActivity.actionSwipe currentAction;
static final int MIN_DISTANCE = 100;
private String finalUrlDownload;
private String preview_url;
private ImageView prev, next;
private boolean isHiding;
private Bitmap downloadedImage;
private File fileVideo;
private TextView progress;
private boolean canSwipe;
2017-12-22 16:48:37 +01:00
private AppBarLayout appBar;
2017-12-23 19:31:12 +01:00
private ProgressBar pbar_inf;
private TextView message_ready;
2017-11-18 12:22:41 +01:00
private enum actionSwipe{
RIGHT_TO_LEFT,
LEFT_TO_RIGHT,
POP
}
private static final int SWIPE_MIN_DISTANCE = 120;
private static final int SWIPE_MAX_OFF_PATH = 250;
private static final int SWIPE_THRESHOLD_VELOCITY = 200;
private GestureDetector gestureDetector;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
gestureDetector = new GestureDetector(new SwipeDetector());
2017-06-30 17:09:07 +02:00
SharedPreferences sharedpreferences = getSharedPreferences(Helper.APP_PREFS, android.content.Context.MODE_PRIVATE);
int theme = sharedpreferences.getInt(Helper.SET_THEME, Helper.THEME_DARK);
2017-06-30 17:09:07 +02:00
if( theme == Helper.THEME_LIGHT){
2017-11-07 11:09:09 +01:00
setTheme(R.style.AppTheme_NoActionBar);
2017-06-30 17:09:07 +02:00
}else {
2017-11-07 11:09:09 +01:00
setTheme(R.style.AppThemeDark_NoActionBar);
2017-06-30 17:09:07 +02:00
}
setContentView(R.layout.activity_media);
attachments = getIntent().getParcelableArrayListExtra("mediaArray");
2017-10-27 15:34:53 +02:00
if( getIntent().getExtras() != null)
mediaPosition = getIntent().getExtras().getInt("position", 1);
if( attachments == null || attachments.size() == 0)
finish();
2017-11-06 19:38:04 +01:00
2017-10-27 15:34:53 +02:00
RelativeLayout main_container_media = findViewById(R.id.main_container_media);
2017-07-01 15:24:28 +02:00
if( theme == Helper.THEME_LIGHT){
main_container_media.setBackgroundResource(R.color.mastodonC2);
2017-07-01 15:24:28 +02:00
}else {
2017-11-07 19:04:02 +01:00
main_container_media.setBackgroundResource(R.color.mastodonC1_);
2017-07-01 15:24:28 +02:00
}
message_ready = findViewById(R.id.message_ready);
2017-11-07 11:09:09 +01:00
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
2017-11-06 19:38:04 +01:00
if( getSupportActionBar() != null) {
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
2017-11-07 11:09:09 +01:00
LayoutInflater inflater = (LayoutInflater) this.getSystemService(android.content.Context.LAYOUT_INFLATER_SERVICE);
assert inflater != null;
@SuppressLint("InflateParams") View view = inflater.inflate(R.layout.picture_actionbar, null);
getSupportActionBar().setCustomView(view, new ActionBar.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
getSupportActionBar().setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM);
ImageView action_save = getSupportActionBar().getCustomView().findViewById(R.id.action_save);
ImageView close = getSupportActionBar().getCustomView().findViewById(R.id.close);
if( close != null){
close.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
finish();
}
});
}
action_save.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if(Build.VERSION.SDK_INT >= 23 ){
if (ContextCompat.checkSelfPermission(getApplicationContext(), Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED ) {
ActivityCompat.requestPermissions(MediaActivity.this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, EXTERNAL_STORAGE_REQUEST_CODE);
} else {
Helper.manageMoveFileDownload(MediaActivity.this, preview_url, finalUrlDownload, downloadedImage, fileVideo);
2017-11-07 11:09:09 +01:00
}
}else{
Helper.manageMoveFileDownload(MediaActivity.this, preview_url, finalUrlDownload, downloadedImage, fileVideo);
2017-11-07 11:09:09 +01:00
}
}
});
2017-11-06 19:38:04 +01:00
Handler h = new Handler();
h.postDelayed(new Runnable() {
@Override
public void run() {
// DO DELAYED STUFF
if(canSwipe)
2017-12-22 16:48:37 +01:00
appBar.setExpanded(false);
2017-11-06 19:38:04 +01:00
}
}, 2000);
}
canSwipe = true;
2017-10-27 15:34:53 +02:00
loader = findViewById(R.id.loader);
imageView = findViewById(R.id.media_picture);
videoView = findViewById(R.id.media_video);
2017-12-22 16:48:37 +01:00
appBar = findViewById(R.id.appBar);
2017-10-27 15:34:53 +02:00
prev = findViewById(R.id.media_prev);
next = findViewById(R.id.media_next);
changeDrawableColor(getApplicationContext(), prev,R.color.mastodonC4);
changeDrawableColor(getApplicationContext(), next,R.color.mastodonC4);
prev.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mediaPosition--;
displayMediaAtPosition(actionSwipe.POP);
}
});
next.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mediaPosition++;
displayMediaAtPosition(actionSwipe.POP);
}
});
imageView.setOnMatrixChangeListener(new OnMatrixChangedListener() {
@Override
public void onMatrixChanged(RectF rect) {
canSwipe = (imageView.getScale() == 1 );
2017-11-06 19:38:04 +01:00
if( !canSwipe && getSupportActionBar() != null && getSupportActionBar().isShowing()){
2017-12-22 16:48:37 +01:00
appBar.setExpanded(false);
2017-11-06 19:38:04 +01:00
}
}
});
2017-10-27 15:34:53 +02:00
progress = findViewById(R.id.loader_progress);
2017-12-23 19:31:12 +01:00
pbar_inf = findViewById(R.id.pbar_inf);
setTitle("");
isHiding = false;
setTitle("");
displayMediaAtPosition(actionSwipe.POP);
}
//It's a part of the code from Hitesh Sahu on stackoverflow. See: https://stackoverflow.com/a/38442055
private class SwipeDetector extends GestureDetector.SimpleOnGestureListener {
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
// Check movement along the Y-axis. If it exceeds SWIPE_MAX_OFF_PATH,
// then dismiss the swipe.
if (Math.abs(e1.getY() - e2.getY()) > SWIPE_MAX_OFF_PATH)
return false;
// Swipe from left to right.
// The swipe needs to exceed a certain distance (SWIPE_MIN_DISTANCE)
// and a certain velocity (SWIPE_THRESHOLD_VELOCITY).
if (e2.getX() - e1.getX() > SWIPE_MIN_DISTANCE && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
finish();
return true;
}
return false;
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
return gestureDetector.onTouchEvent(event);
}
/**
* Manage touch event
* Allows to swipe from timelines
* @param event MotionEvent
* @return boolean
*/
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
if (gestureDetector != null && imageView.getScale() == 1 && mediaPosition == 1) {
if (gestureDetector.onTouchEvent(event))
// If the gestureDetector handles the event, a swipe has been
// executed and no more needs to be done.
return true;
}
2017-11-06 19:38:04 +01:00
if( event.getAction() == MotionEvent.ACTION_DOWN){
2017-12-22 16:48:37 +01:00
if( getSupportActionBar() != null && canSwipe) {
appBar.setExpanded(true);
2017-11-06 19:38:04 +01:00
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
@Override
public void run() {
2017-12-22 16:48:37 +01:00
appBar.setExpanded(false);
2017-11-06 19:38:04 +01:00
}
}, 2000);
}
}
if( !canSwipe || mediaPosition > attachments.size() || mediaPosition < 1 || attachments.size() <= 1)
return super.dispatchTouchEvent(event);
switch(event.getAction()){
case MotionEvent.ACTION_DOWN: {
downX = event.getX();
//Displays navigation left/right buttons
if( attachments != null && attachments.size() > 1 && !isHiding){
prev.setVisibility(View.VISIBLE);
next.setVisibility(View.VISIBLE);
isHiding = true;
new Handler().postDelayed(new Runnable(){
public void run() {
prev.setVisibility(View.GONE);
next.setVisibility(View.GONE);
isHiding = false;
}
}, 2000);
}
return super.dispatchTouchEvent(event);
}
case MotionEvent.ACTION_UP: {
float upX = event.getX();
float deltaX = downX - upX;
// swipe horizontal
2017-07-10 09:24:58 +02:00
if( downX > MIN_DISTANCE & (Math.abs(deltaX) > MIN_DISTANCE ) ){
if(deltaX < 0) { switchOnSwipe(MediaActivity.actionSwipe.LEFT_TO_RIGHT); return true; }
if(deltaX > 0) { switchOnSwipe(MediaActivity.actionSwipe.RIGHT_TO_LEFT); return true; }
}else{
currentAction = MediaActivity.actionSwipe.POP;
}
}
}
return super.dispatchTouchEvent(event);
}
private void switchOnSwipe(actionSwipe action){
loader.setVisibility(View.VISIBLE);
mediaPosition = (action == actionSwipe.LEFT_TO_RIGHT)?mediaPosition-1:mediaPosition+1;
displayMediaAtPosition(action);
}
private void displayMediaAtPosition(actionSwipe action){
if( mediaPosition > attachments.size() )
mediaPosition = 1;
if( mediaPosition < 1)
mediaPosition = attachments.size();
currentAction = action;
final Attachment attachment = attachments.get(mediaPosition-1);
String type = attachment.getType();
String url = attachment.getUrl();
finalUrlDownload = url;
videoView.setVisibility(View.GONE);
if( videoView.isPlaying()) {
videoView.stopPlayback();
}
imageView.setVisibility(View.GONE);
preview_url = attachment.getPreview_url();
2017-10-18 17:07:50 +02:00
if( type.equals("unknown")){
preview_url = attachment.getRemote_url();
if( preview_url.endsWith(".png") || preview_url.endsWith(".jpg")|| preview_url.endsWith(".jpeg")) {
2017-10-18 17:07:50 +02:00
type = "image";
}else if( preview_url.endsWith(".mp4")) {
2017-10-18 17:07:50 +02:00
type = "video";
}
url = attachment.getRemote_url();
attachment.setType(type);
2017-10-18 17:07:50 +02:00
}
2017-11-18 12:22:41 +01:00
final String finalUrl = url;
switch (type){
case "image":
pbar_inf.setScaleY(1f);
2017-12-23 19:31:12 +01:00
imageView.setVisibility(View.VISIBLE);
fileVideo = null;
pbar_inf.setIndeterminate(true);
loader.setVisibility(View.VISIBLE);
Glide.with(getApplicationContext())
.asBitmap()
.load(preview_url).listener(new RequestListener<Bitmap>() {
@Override
public boolean onResourceReady(Bitmap resource, Object model, Target<Bitmap> target, DataSource dataSource, boolean isFirstResource) {
Glide.with(getApplicationContext())
.asBitmap()
.load(finalUrl)
.listener(new RequestListener<Bitmap>() {
@Override
public boolean onResourceReady(Bitmap resource, Object model, Target<Bitmap> target, DataSource dataSource, boolean isFirstResource) {
return false;
}
@Override
public boolean onLoadFailed(@Nullable GlideException e, Object model, Target target, boolean isFirstResource) {
loader.setVisibility(View.GONE);
return false;
}
})
.into(new SimpleTarget<Bitmap>() {
@Override
public void onResourceReady(final Bitmap resource, Transition<? super Bitmap> transition) {
loader.setVisibility(View.GONE);
if( imageView.getScale() < 1.1) {
downloadedImage = resource;
imageView.setImageBitmap(resource);
}else{
message_ready.setVisibility(View.VISIBLE);
}
message_ready.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
downloadedImage = resource;
imageView.setImageBitmap(resource);
message_ready.setVisibility(View.GONE);
}
});
fileVideo = null;
}
});
return false;
}
@Override
public boolean onLoadFailed(@Nullable GlideException e, Object model, Target target, boolean isFirstResource) {
Glide.with(getApplicationContext())
.asBitmap()
.load(finalUrl)
.listener(new RequestListener<Bitmap>() {
@Override
public boolean onResourceReady(Bitmap resource, Object model, Target<Bitmap> target, DataSource dataSource, boolean isFirstResource) {
return false;
}
@Override
public boolean onLoadFailed(@Nullable GlideException e, Object model, Target target, boolean isFirstResource) {
loader.setVisibility(View.GONE);
return false;
}
})
.into(new SimpleTarget<Bitmap>() {
@Override
public void onResourceReady(final Bitmap resource, Transition<? super Bitmap> transition) {
loader.setVisibility(View.GONE);
if( imageView.getScale() < 1.1) {
downloadedImage = resource;
imageView.setImageBitmap(resource);
}else{
message_ready.setVisibility(View.VISIBLE);
}
message_ready.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
downloadedImage = resource;
imageView.setImageBitmap(resource);
message_ready.setVisibility(View.GONE);
}
});
fileVideo = null;
}
});
return false;
}
}).into(imageView);
break;
case "video":
case "gifv":
2017-12-23 19:31:12 +01:00
pbar_inf.setIndeterminate(false);
pbar_inf.setScaleY(3f);
2017-11-18 12:22:41 +01:00
File file = new File(getCacheDir() + "/" + Helper.md5(url)+".mp4");
if(file.exists()) {
Uri uri = Uri.parse(file.getAbsolutePath());
videoView.setVisibility(View.VISIBLE);
videoView.setVideoURI(uri);
videoView.start();
MediaController mc = new MediaController(MediaActivity.this);
videoView.setMediaController(mc);
videoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
@Override
public void onPrepared(MediaPlayer mp) {
loader.setVisibility(View.GONE);
mp.start();
mp.setLooping(true);
}
});
fileVideo = file;
downloadedImage = null;
}else{
2017-12-24 08:56:08 +01:00
videoView.setVisibility(View.VISIBLE);
Uri uri = Uri.parse(url);
videoView.setVideoURI(uri);
videoView.start();
MediaController mc = new MediaController(MediaActivity.this);
mc.setAnchorView(videoView);
videoView.setMediaController(mc);
videoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
@Override
public void onPrepared(MediaPlayer mp) {
mp.start();
mp.setLooping(true);
}
});
videoView.start();
progress.setText("0 %");
progress.setVisibility(View.VISIBLE);
new HttpsConnection(MediaActivity.this).download(finalUrl, MediaActivity.this );
}
break;
}
String filename = URLUtil.guessFileName(url, null, null);
if( filename == null)
filename = url;
2017-07-10 09:24:58 +02:00
if( attachments.size() > 1 )
filename = String.format("%s (%s/%s)",filename, mediaPosition, attachments.size());
ActionBar actionBar = getSupportActionBar();
if( actionBar != null){
2017-11-07 11:09:09 +01:00
TextView picture_actionbar_title = actionBar.getCustomView().findViewById(R.id.toolbar_title);
picture_actionbar_title.setText(filename);
}else {
setTitle(url);
}
}
2017-11-18 12:22:41 +01:00
@Override
2017-12-07 18:48:18 +01:00
public void onDownloaded(String path, String originUrl, Error error) {
File response = new File(path);
File dir = getCacheDir();
File from = new File(dir, response.getName());
File to = new File(dir, Helper.md5(originUrl) + ".mp4");
if (from.exists())
//noinspection ResultOfMethodCallIgnored
from.renameTo(to);
fileVideo = to;
downloadedImage = null;
2017-11-18 12:22:41 +01:00
progress.setVisibility(View.GONE);
2017-12-24 08:56:08 +01:00
loader.setVisibility(View.GONE);
2017-11-18 12:22:41 +01:00
}
2017-11-18 12:36:10 +01:00
2017-11-18 12:22:41 +01:00
@Override
public void onUpdateProgress(int progressPercentage) {
progress.setText(String.format("%s%%",String.valueOf(progressPercentage)));
pbar_inf.setProgress(progressPercentage);
2017-11-18 12:22:41 +01:00
}
}