diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index f96b6fdfd..462771183 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -313,6 +313,12 @@
android:theme="@style/Theme.Transparent"
android:configChanges="keyboardHidden|orientation|screenSize"
android:noHistory="true" />
+
. */
+package app.fedilab.android.activities;
+
+
+
+import android.content.SharedPreferences;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.GestureDetector;
+import android.view.MotionEvent;
+import android.view.ViewGroup;
+import android.widget.RelativeLayout;
+
+import androidx.coordinatorlayout.widget.CoordinatorLayout;
+import androidx.fragment.app.Fragment;
+import androidx.fragment.app.FragmentManager;
+import androidx.fragment.app.FragmentStatePagerAdapter;
+import androidx.viewpager.widget.PagerAdapter;
+import androidx.viewpager.widget.ViewPager;
+
+
+import org.jetbrains.annotations.NotNull;
+
+import java.util.ArrayList;
+
+import app.fedilab.android.R;
+import app.fedilab.android.client.Entities.Attachment;
+import app.fedilab.android.fragments.MediaSliderFragment;
+import app.fedilab.android.helper.Helper;
+
+
+
+/**
+ * Created by Thomas on 25/06/2017.
+ * Media Activity
+ */
+
+public class SlideMediaActivity extends BaseActivity {
+
+ private ArrayList attachments;
+ private int mediaPosition;
+ private ViewPager mPager;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ SharedPreferences sharedpreferences = getSharedPreferences(Helper.APP_PREFS, MODE_PRIVATE);
+ int theme = sharedpreferences.getInt(Helper.SET_THEME, Helper.THEME_DARK);
+ if (theme == Helper.THEME_BLACK)
+ setTheme(R.style.TransparentBlack);
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_media_pager);
+ supportPostponeEnterTransition();
+ supportStartPostponedEnterTransition();
+ CoordinatorLayout main_container_media = findViewById(R.id.main_container_media);
+ if (theme == Helper.THEME_LIGHT) {
+ main_container_media.setBackgroundResource(R.color.mastodonC2);
+ } else if (theme == Helper.THEME_BLACK) {
+ main_container_media.setBackgroundResource(R.color.black);
+ } else if (theme == Helper.THEME_DARK) {
+ main_container_media.setBackgroundResource(R.color.mastodonC1_);
+ }
+ attachments = getIntent().getParcelableArrayListExtra("mediaArray");
+ if (getIntent().getExtras() != null)
+ mediaPosition = getIntent().getExtras().getInt("position", 1);
+ gestureDetector = new GestureDetector(new SwipeDetector());
+
+ if (attachments == null || attachments.size() == 0)
+ finish();
+ mPager = findViewById(R.id.media_viewpager);
+
+ PagerAdapter mPagerAdapter = new ScreenSlidePagerAdapter(getSupportFragmentManager());
+ mPager.setAdapter(mPagerAdapter);
+
+ mPager.setCurrentItem(mediaPosition-1);
+
+ }
+
+ private MediaSliderFragment mCurrentFragment;
+
+
+ public MediaSliderFragment getCurrentFragment() {
+ return mCurrentFragment;
+ }
+
+ /**
+ * Media Pager
+ */
+ private class ScreenSlidePagerAdapter extends FragmentStatePagerAdapter {
+
+ ScreenSlidePagerAdapter(FragmentManager fm) {
+ super(fm);
+ }
+
+ @NotNull
+ @Override
+ public Fragment getItem(int position) {
+ Bundle bundle = new Bundle();
+ MediaSliderFragment mediaSliderFragment = new MediaSliderFragment();
+ bundle.putInt("position", position);
+ Log.v(Helper.TAG,"position: " + position);
+ Log.v(Helper.TAG,"attachments.get(position): " + attachments.get(position));
+ bundle.putParcelable("attachment", attachments.get(position));
+ mediaSliderFragment.setArguments(bundle);
+ return mediaSliderFragment;
+ }
+
+ @Override
+ public void setPrimaryItem(@NotNull ViewGroup container, int position, @NotNull Object object) {
+ if (getCurrentFragment() != object) {
+ mCurrentFragment = ((MediaSliderFragment) object);
+ }
+ super.setPrimaryItem(container, position, object);
+ }
+
+ @Override
+ public int getCount() {
+ return attachments.size();
+ }
+ }
+
+ 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;
+
+ 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.getX() - e2.getX()) > 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.getY() - e1.getY() > SWIPE_MIN_DISTANCE && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
+ if( mCurrentFragment.canSwipe()) {
+ finish();
+ return true;
+ }else{
+ return false;
+ }
+ }
+
+ return false;
+ }
+ }
+
+
+ @Override
+ public boolean dispatchTouchEvent(MotionEvent ev) {
+ // TouchEvent dispatcher.
+ if (gestureDetector != null) {
+ if (gestureDetector.onTouchEvent(ev))
+ // If the gestureDetector handles the event, a swipe has been
+ // executed and no more needs to be done.
+ return true;
+ }
+ return super.dispatchTouchEvent(ev);
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent event) {
+ return gestureDetector.onTouchEvent(event);
+ }
+
+}
diff --git a/app/src/main/java/app/fedilab/android/drawers/ArtListAdapter.java b/app/src/main/java/app/fedilab/android/drawers/ArtListAdapter.java
index 6ddd5d45a..9500c7a58 100644
--- a/app/src/main/java/app/fedilab/android/drawers/ArtListAdapter.java
+++ b/app/src/main/java/app/fedilab/android/drawers/ArtListAdapter.java
@@ -15,6 +15,7 @@ package app.fedilab.android.drawers;
* see . */
import android.annotation.SuppressLint;
+import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
@@ -22,6 +23,8 @@ import android.database.sqlite.SQLiteDatabase;
import android.os.Bundle;
import androidx.annotation.NonNull;
+import androidx.core.app.ActivityOptionsCompat;
+import androidx.core.view.ViewCompat;
import androidx.recyclerview.widget.RecyclerView;
import android.view.LayoutInflater;
@@ -38,6 +41,7 @@ import com.bumptech.glide.Glide;
import java.util.ArrayList;
import java.util.List;
+import app.fedilab.android.activities.SlideMediaActivity;
import app.fedilab.android.client.API;
import app.fedilab.android.client.APIResponse;
import app.fedilab.android.client.Entities.Attachment;
@@ -203,7 +207,7 @@ public class ArtListAdapter extends RecyclerView.Adapter implements OnPostAction
holder.art_media.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
- Intent intent = new Intent(context, MediaActivity.class);
+ Intent intent = new Intent(context, SlideMediaActivity.class);
Bundle b = new Bundle();
ArrayList attachments = new ArrayList<>();
if (status.getArt_attachment() != null)
@@ -213,7 +217,9 @@ public class ArtListAdapter extends RecyclerView.Adapter implements OnPostAction
intent.putParcelableArrayListExtra("mediaArray", attachments);
b.putInt("position", 0);
intent.putExtras(b);
- context.startActivity(intent);
+ ViewCompat.setTransitionName(v, status.getMedia_attachments().get(0).getUrl());
+ ActivityOptionsCompat options = ActivityOptionsCompat.makeSceneTransitionAnimation((Activity) context, v, status.getMedia_attachments().get(0).getUrl());
+ context.startActivity(intent, options.toBundle());
}
});
holder.art_author.setOnClickListener(new View.OnClickListener() {
diff --git a/app/src/main/java/app/fedilab/android/drawers/ImageAdapter.java b/app/src/main/java/app/fedilab/android/drawers/ImageAdapter.java
index 048d20b9c..21a5ad8f3 100644
--- a/app/src/main/java/app/fedilab/android/drawers/ImageAdapter.java
+++ b/app/src/main/java/app/fedilab/android/drawers/ImageAdapter.java
@@ -14,11 +14,14 @@ package app.fedilab.android.drawers;
* You should have received a copy of the GNU General Public License along with Fedilab; if not,
* see . */
+import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import androidx.annotation.NonNull;
+import androidx.core.app.ActivityOptionsCompat;
+import androidx.core.view.ViewCompat;
import androidx.recyclerview.widget.RecyclerView;
import android.view.LayoutInflater;
@@ -31,6 +34,7 @@ import com.bumptech.glide.Glide;
import java.util.ArrayList;
import java.util.List;
+import app.fedilab.android.activities.SlideMediaActivity;
import app.fedilab.android.client.Entities.Attachment;
import app.fedilab.android.client.Entities.Status;
import app.fedilab.android.R;
@@ -79,7 +83,7 @@ public class ImageAdapter extends RecyclerView.Adapter {
holder.imageView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
- Intent intent = new Intent(context, MediaActivity.class);
+ Intent intent = new Intent(context, SlideMediaActivity.class);
Bundle b = new Bundle();
ArrayList attachmentsTmp = new ArrayList<>();
for (Status status1 : statuses) {
@@ -88,7 +92,9 @@ public class ImageAdapter extends RecyclerView.Adapter {
intent.putParcelableArrayListExtra("mediaArray", attachmentsTmp);
b.putInt("position", (viewHolder.getAdapterPosition() + 1));
intent.putExtras(b);
- context.startActivity(intent);
+ ViewCompat.setTransitionName(v, status.getMedia_attachments().get(0).getUrl());
+ ActivityOptionsCompat options = ActivityOptionsCompat.makeSceneTransitionAnimation((Activity) context, v, status.getMedia_attachments().get(0).getUrl());
+ context.startActivity(intent, options.toBundle());
}
});
holder.imageView.setOnLongClickListener(new View.OnLongClickListener() {
diff --git a/app/src/main/java/app/fedilab/android/drawers/NotificationsListAdapter.java b/app/src/main/java/app/fedilab/android/drawers/NotificationsListAdapter.java
index a8fa57898..4febdc014 100644
--- a/app/src/main/java/app/fedilab/android/drawers/NotificationsListAdapter.java
+++ b/app/src/main/java/app/fedilab/android/drawers/NotificationsListAdapter.java
@@ -32,9 +32,11 @@ import android.os.Handler;
import androidx.annotation.NonNull;
import androidx.constraintlayout.widget.ConstraintLayout;
+import androidx.core.app.ActivityOptionsCompat;
import androidx.core.content.ContextCompat;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.widget.PopupMenu;
+import androidx.core.view.ViewCompat;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
@@ -75,6 +77,7 @@ import java.util.TimerTask;
import app.fedilab.android.activities.AccountReportActivity;
import app.fedilab.android.activities.BaseMainActivity;
import app.fedilab.android.activities.OwnerNotificationChartsActivity;
+import app.fedilab.android.activities.SlideMediaActivity;
import app.fedilab.android.client.API;
import app.fedilab.android.client.APIResponse;
import app.fedilab.android.client.Entities.Account;
@@ -1380,12 +1383,14 @@ public class NotificationsListAdapter extends RecyclerView.Adapter implements On
imageView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
- Intent intent = new Intent(context, MediaActivity.class);
+ Intent intent = new Intent(context, SlideMediaActivity.class);
Bundle b = new Bundle();
intent.putParcelableArrayListExtra("mediaArray", notification.getStatus().getMedia_attachments());
b.putInt("position", finalPosition);
intent.putExtras(b);
- context.startActivity(intent);
+ ViewCompat.setTransitionName(v, notification.getStatus().getMedia_attachments().get(0).getUrl());
+ ActivityOptionsCompat options = ActivityOptionsCompat.makeSceneTransitionAnimation((Activity) context, v, notification.getStatus().getMedia_attachments().get(0).getUrl());
+ context.startActivity(intent, options.toBundle());
}
});
i++;
diff --git a/app/src/main/java/app/fedilab/android/drawers/PixelfedListAdapter.java b/app/src/main/java/app/fedilab/android/drawers/PixelfedListAdapter.java
index 8a160597a..ef89ca75d 100644
--- a/app/src/main/java/app/fedilab/android/drawers/PixelfedListAdapter.java
+++ b/app/src/main/java/app/fedilab/android/drawers/PixelfedListAdapter.java
@@ -33,8 +33,10 @@ import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.widget.PopupMenu;
import androidx.constraintlayout.widget.ConstraintLayout;
+import androidx.core.app.ActivityOptionsCompat;
import androidx.core.content.ContextCompat;
import androidx.cardview.widget.CardView;
+import androidx.core.view.ViewCompat;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
@@ -80,6 +82,7 @@ import java.util.List;
import app.fedilab.android.activities.MediaActivity;
import app.fedilab.android.activities.PixelfedComposeActivity;
+import app.fedilab.android.activities.SlideMediaActivity;
import app.fedilab.android.activities.TootActivity;
import app.fedilab.android.activities.TootInfoActivity;
import app.fedilab.android.asynctasks.PostActionAsyncTask;
@@ -481,12 +484,14 @@ public class PixelfedListAdapter extends RecyclerView.Adapter implements OnPostA
holder.art_media.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
- Intent intent = new Intent(context, MediaActivity.class);
+ Intent intent = new Intent(context, SlideMediaActivity.class);
Bundle b = new Bundle();
intent.putParcelableArrayListExtra("mediaArray", status.getMedia_attachments());
b.putInt("position", 0);
intent.putExtras(b);
- context.startActivity(intent);
+ ViewCompat.setTransitionName(v, status.getMedia_attachments().get(0).getUrl());
+ ActivityOptionsCompat options = ActivityOptionsCompat.makeSceneTransitionAnimation((Activity) context, v, status.getMedia_attachments().get(0).getUrl());
+ context.startActivity(intent, options.toBundle());
}
});
diff --git a/app/src/main/java/app/fedilab/android/drawers/SliderAdapter.java b/app/src/main/java/app/fedilab/android/drawers/SliderAdapter.java
index bedf85881..f8754093f 100644
--- a/app/src/main/java/app/fedilab/android/drawers/SliderAdapter.java
+++ b/app/src/main/java/app/fedilab/android/drawers/SliderAdapter.java
@@ -36,6 +36,7 @@ import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi;
import androidx.appcompat.app.AlertDialog;
+import androidx.core.app.ActivityOptionsCompat;
import com.bumptech.glide.Glide;
import com.bumptech.glide.request.target.SimpleTarget;
@@ -49,6 +50,7 @@ import java.util.List;
import app.fedilab.android.R;
import app.fedilab.android.activities.MediaActivity;
import app.fedilab.android.activities.PixelfedComposeActivity;
+import app.fedilab.android.activities.SlideMediaActivity;
import app.fedilab.android.asynctasks.UpdateDescriptionAttachmentAsyncTask;
import app.fedilab.android.client.Entities.Attachment;
import app.fedilab.android.client.Entities.Error;
@@ -105,13 +107,14 @@ public class SliderAdapter extends SliderViewAdapter. */
+
+import android.Manifest;
+import android.app.Activity;
+import android.content.Context;
+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.AsyncTask;
+import android.os.Build;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+import android.webkit.WebView;
+import android.widget.FrameLayout;
+import android.widget.ImageButton;
+import android.widget.ImageView;
+import android.widget.ProgressBar;
+import android.widget.RelativeLayout;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import androidx.annotation.NonNull;
+import androidx.core.app.ActivityCompat;
+import androidx.core.content.ContextCompat;
+import androidx.fragment.app.Fragment;
+import androidx.recyclerview.widget.GridLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+
+import com.bumptech.glide.Glide;
+import com.bumptech.glide.request.target.SimpleTarget;
+import com.bumptech.glide.request.transition.Transition;
+import com.cleveroad.audiovisualization.DbmHandler;
+import com.cleveroad.audiovisualization.GLAudioVisualizationView;
+import com.github.chrisbanes.photoview.OnMatrixChangedListener;
+import com.github.chrisbanes.photoview.PhotoView;
+import com.google.android.exoplayer2.ExoPlayerFactory;
+import com.google.android.exoplayer2.Player;
+import com.google.android.exoplayer2.SimpleExoPlayer;
+import com.google.android.exoplayer2.source.ExtractorMediaSource;
+import com.google.android.exoplayer2.ui.SimpleExoPlayerView;
+import com.google.android.exoplayer2.upstream.DataSource;
+import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory;
+import com.google.android.exoplayer2.util.Util;
+import com.gw.swipeback.SwipeBackLayout;
+
+import org.jetbrains.annotations.NotNull;
+
+import java.io.File;
+import java.security.KeyManagementException;
+import java.security.NoSuchAlgorithmException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Timer;
+import java.util.TimerTask;
+
+import javax.net.ssl.HttpsURLConnection;
+
+import app.fedilab.android.R;
+import app.fedilab.android.activities.MediaActivity;
+import app.fedilab.android.asynctasks.RetrieveFeedsAsyncTask;
+import app.fedilab.android.client.APIResponse;
+import app.fedilab.android.client.Entities.Attachment;
+import app.fedilab.android.client.Entities.Error;
+import app.fedilab.android.client.Entities.Status;
+import app.fedilab.android.client.HttpsConnection;
+import app.fedilab.android.client.TLSSocketFactory;
+import app.fedilab.android.drawers.ImageAdapter;
+import app.fedilab.android.helper.Helper;
+import app.fedilab.android.interfaces.OnDownloadInterface;
+import app.fedilab.android.interfaces.OnRetrieveFeedsInterface;
+import app.fedilab.android.webview.MastalabWebChromeClient;
+import app.fedilab.android.webview.MastalabWebViewClient;
+import cafe.adriel.androidaudiorecorder.VisualizerHandler;
+import es.dmoral.toasty.Toasty;
+
+import static android.content.Context.MODE_PRIVATE;
+import static app.fedilab.android.helper.Helper.changeDrawableColor;
+import static cafe.adriel.androidaudiorecorder.Util.formatSeconds;
+import static cafe.adriel.androidaudiorecorder.Util.getDarkerColor;
+
+
+/**
+ * Created by Thomas on 09/10/2019.
+ * Fragment to display media from SlideMediaActivity
+ */
+public class MediaSliderFragment extends Fragment implements OnDownloadInterface, MediaPlayer.OnCompletionListener {
+
+
+ private boolean flag_loading;
+ private Context context;
+ private AsyncTask asyncTask;
+ private String max_id;
+ private RelativeLayout mainLoader, nextElementLoader, textviewNoAction;
+ private boolean firstLoad;
+ private String targetedId;
+ private boolean showMediaOnly, showPinned, showReply;
+ boolean firstTootsLoaded;
+ private SharedPreferences sharedpreferences;
+ private ArrayList statuses;
+ private ImageAdapter gridAdaper;
+ private RecyclerView gridview;
+ private int mediaPosition;
+
+
+
+ private WebView webview_video;
+ private ImageButton media_save, media_share, media_close;
+ private boolean scheduleHidden, scheduleHiddenDescription;
+ private SimpleExoPlayer player;
+ private boolean isSHaring;
+ private String instance;
+ private RelativeLayout content_audio;
+ private MediaPlayer playeraudio;
+ private Timer timer;
+ private int playerSecondsElapsed;
+ private static final Handler HANDLER = new Handler();
+ private String url;
+
+ private RelativeLayout loader;
+ private ArrayList attachments;
+ private PhotoView imageView;
+ private SimpleExoPlayerView videoView;
+ private float downX;
+ private float downY;
+ static final int MIN_DISTANCE = 100;
+ private String finalUrlDownload;
+ private String preview_url;
+ private ImageView prev, next;
+ private boolean isControlElementShown = true;
+ private Bitmap downloadedImage;
+ private File fileVideo;
+ private TextView progress;
+ private ProgressBar pbar_inf;
+ private TextView message_ready;
+ private boolean canSwipe;
+ private TextView media_description;
+ private Attachment attachment;
+ private float imageScale = 0;
+ private RelativeLayout action_bar_container;
+ private VisualizerHandler visualizerHandler;
+ private TextView statusView;
+ private TextView timerView;
+ private ImageButton playView;
+ private GLAudioVisualizationView visualizerView;
+ public MediaSliderFragment() {
+ }
+
+ @Override
+ public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+ View rootView = inflater.inflate(R.layout.fragment_slide_media, container, false);
+
+ context = getContext();
+ Bundle bundle = this.getArguments();
+
+ if (bundle != null) {
+ mediaPosition = bundle.getInt("position", 1);
+ attachment = bundle.getParcelable("attachment");
+ }
+ Log.v(Helper.TAG,mediaPosition + " -> " + attachment);
+ media_description = rootView.findViewById(R.id.media_description);
+ message_ready = rootView.findViewById(R.id.message_ready);
+ media_save = rootView.findViewById(R.id.media_save);
+ media_share = rootView.findViewById(R.id.media_share);
+ media_close = rootView.findViewById(R.id.media_close);
+ progress = rootView.findViewById(R.id.loader_progress);
+ webview_video = rootView.findViewById(R.id.webview_video);
+ content_audio = rootView.findViewById(R.id.content_audio);
+ media_save.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ isSHaring = false;
+ if (attachment.getType().toLowerCase().equals("video") || attachment.getType().toLowerCase().equals("audio") || attachment.getType().toLowerCase().equals("gifv") || attachment.getType().toLowerCase().equals("web")) {
+ if (attachment != null) {
+ progress.setText("0 %");
+ progress.setVisibility(View.VISIBLE);
+ new HttpsConnection(context, instance).download(attachment.getUrl(), MediaSliderFragment.this);
+ }
+ } else {
+ if (Build.VERSION.SDK_INT >= 23) {
+ if (ContextCompat.checkSelfPermission(context, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
+ ActivityCompat.requestPermissions((Activity)context, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, Helper.EXTERNAL_STORAGE_REQUEST_CODE);
+ } else {
+ Helper.manageMoveFileDownload(context, preview_url, finalUrlDownload, downloadedImage, fileVideo, false);
+ }
+ } else {
+ Helper.manageMoveFileDownload(context, preview_url, finalUrlDownload, downloadedImage, fileVideo, false);
+ }
+ }
+ }
+ });
+ media_share.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ isSHaring = true;
+ if (attachment.getType().toLowerCase().equals("video") || attachment.getType().toLowerCase().equals("audio") || attachment.getType().toLowerCase().equals("gifv")) {
+ if (attachment != null) {
+ progress.setText("0 %");
+ progress.setVisibility(View.VISIBLE);
+ new HttpsConnection(context, instance).download(attachment.getUrl(), MediaSliderFragment.this);
+ }
+ } else {
+ if (Build.VERSION.SDK_INT >= 23) {
+ if (ContextCompat.checkSelfPermission(context, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
+ ActivityCompat.requestPermissions((Activity)context, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, Helper.EXTERNAL_STORAGE_REQUEST_CODE);
+ } else {
+ Helper.manageMoveFileDownload(context, preview_url, finalUrlDownload, downloadedImage, fileVideo, true);
+ }
+ } else {
+ Helper.manageMoveFileDownload(context, preview_url, finalUrlDownload, downloadedImage, fileVideo, true);
+ }
+ }
+ }
+ });
+ media_close.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ ((Activity)context).finish();
+ }
+ });
+ sharedpreferences = context.getSharedPreferences(Helper.APP_PREFS, MODE_PRIVATE);
+ int theme = sharedpreferences.getInt(Helper.SET_THEME, Helper.THEME_DARK);
+
+ loader = rootView.findViewById(R.id.loader);
+ imageView = rootView.findViewById(R.id.media_picture);
+ videoView = rootView.findViewById(R.id.media_video);
+ prev = rootView.findViewById(R.id.media_prev);
+ next = rootView.findViewById(R.id.media_next);
+ if (theme == Helper.THEME_BLACK) {
+ changeDrawableColor(context, prev, R.color.dark_icon);
+ changeDrawableColor(context, next, R.color.dark_icon);
+ } else if (theme == Helper.THEME_LIGHT) {
+ changeDrawableColor(context, prev, R.color.mastodonC4);
+ changeDrawableColor(context, next, R.color.mastodonC4);
+ } else {
+ changeDrawableColor(context, prev, R.color.white);
+ changeDrawableColor(context, next, R.color.white);
+ }
+ prev.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ mediaPosition--;
+ }
+ });
+ next.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ mediaPosition++;
+ }
+ });
+
+ url = attachment.getUrl();
+ imageView.setOnMatrixChangeListener(new OnMatrixChangedListener() {
+ @Override
+ public void onMatrixChanged(RectF rect) {
+ imageScale = imageView.getScale();
+ canSwipe = (imageView.getScale() == 1);
+ }
+ });
+ if (attachments != null && attachments.size() > 1) {
+ prev.setVisibility(View.VISIBLE);
+ next.setVisibility(View.VISIBLE);
+ }
+ pbar_inf = rootView.findViewById(R.id.pbar_inf);
+ String type = attachment.getType();
+ preview_url = attachment.getPreview_url();
+ if (type.equals("unknown")) {
+ preview_url = attachment.getRemote_url();
+ if (preview_url.endsWith(".png") || preview_url.endsWith(".jpg") || preview_url.endsWith(".jpeg") || preview_url.endsWith(".gif")) {
+ type = "image";
+ } else if (preview_url.endsWith(".mp4") || preview_url.endsWith(".mp3")) {
+ type = "video";
+ }
+ url = attachment.getRemote_url();
+ attachment.setType(type);
+ }
+
+ switch (type.toLowerCase()) {
+ case "image":
+ pbar_inf.setScaleY(1f);
+ imageView.setVisibility(View.VISIBLE);
+ fileVideo = null;
+ pbar_inf.setIndeterminate(true);
+ loader.setVisibility(View.VISIBLE);
+ fileVideo = null;
+ if (!url.endsWith(".gif")) {
+ Glide.with(context)
+ .asBitmap()
+ .load(preview_url).into(
+ new SimpleTarget() {
+ @Override
+ public void onResourceReady(@NonNull final Bitmap resource, Transition super Bitmap> transition) {
+ Bitmap imageCompressed = Helper.compressImageIfNeeded(context, resource);
+ imageView.setImageBitmap(imageCompressed);
+ Glide.with(context)
+ .asBitmap()
+ .load(url).into(
+ new SimpleTarget() {
+ @Override
+ public void onResourceReady(@NonNull final Bitmap resource, Transition super Bitmap> transition) {
+ loader.setVisibility(View.GONE);
+ Bitmap imageCompressed = Helper.compressImageIfNeeded(context, resource);
+ if (imageView.getScale() < 1.1) {
+ downloadedImage = resource;
+ imageView.setImageBitmap(imageCompressed);
+ } else {
+ message_ready.setVisibility(View.VISIBLE);
+ }
+ message_ready.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ downloadedImage = resource;
+ imageView.setImageBitmap(imageCompressed);
+ message_ready.setVisibility(View.GONE);
+ }
+ });
+ }
+ }
+ );
+ }
+ }
+ );
+ } else {
+ loader.setVisibility(View.GONE);
+ Glide.with(context)
+ .load(url).into(imageView);
+ }
+ break;
+ case "video":
+ case "gifv":
+ pbar_inf.setIndeterminate(false);
+ pbar_inf.setScaleY(3f);
+ try {
+ HttpsURLConnection.setDefaultSSLSocketFactory(new TLSSocketFactory(instance));
+ } catch (KeyManagementException e) {
+ e.printStackTrace();
+ } catch (NoSuchAlgorithmException e) {
+ e.printStackTrace();
+ }
+ videoView.setVisibility(View.VISIBLE);
+ Uri uri = Uri.parse(url);
+ DataSource.Factory dataSourceFactory = new DefaultDataSourceFactory(context,
+ Util.getUserAgent(context, "Fedilab"), null);
+ ExtractorMediaSource videoSource = new ExtractorMediaSource.Factory(dataSourceFactory)
+ .createMediaSource(uri);
+ player = ExoPlayerFactory.newSimpleInstance(context);
+ if (type.toLowerCase().equals("gifv"))
+ player.setRepeatMode(Player.REPEAT_MODE_ONE);
+ videoView.setPlayer(player);
+ loader.setVisibility(View.GONE);
+ player.prepare(videoSource);
+ player.setPlayWhenReady(true);
+ break;
+ case "web":
+ loader.setVisibility(View.GONE);
+ webview_video = Helper.initializeWebview((Activity)context, R.id.webview_video);
+ webview_video.setVisibility(View.VISIBLE);
+ FrameLayout webview_container = rootView.findViewById(R.id.main_media_frame);
+ final ViewGroup videoLayout = rootView.findViewById(R.id.videoLayout);
+
+ MastalabWebChromeClient mastalabWebChromeClient = new MastalabWebChromeClient((Activity)context, webview_video, webview_container, videoLayout);
+ mastalabWebChromeClient.setOnToggledFullscreen(new MastalabWebChromeClient.ToggledFullscreenCallback() {
+ @Override
+ public void toggledFullscreen(boolean fullscreen) {
+
+ if (fullscreen) {
+ videoLayout.setVisibility(View.VISIBLE);
+ WindowManager.LayoutParams attrs = ((Activity)context).getWindow().getAttributes();
+ attrs.flags |= WindowManager.LayoutParams.FLAG_FULLSCREEN;
+ attrs.flags |= WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
+ ((Activity)context).getWindow().setAttributes(attrs);
+ ((Activity)context).getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE);
+ } else {
+ WindowManager.LayoutParams attrs = ((Activity)context).getWindow().getAttributes();
+ attrs.flags &= ~WindowManager.LayoutParams.FLAG_FULLSCREEN;
+ attrs.flags &= ~WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
+ ((Activity)context).getWindow().setAttributes(attrs);
+ ((Activity)context).getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE);
+ videoLayout.setVisibility(View.GONE);
+ }
+ }
+ });
+ webview_video.getSettings().setAllowFileAccess(true);
+ webview_video.setWebChromeClient(mastalabWebChromeClient);
+ webview_video.getSettings().setDomStorageEnabled(true);
+ webview_video.getSettings().setAppCacheEnabled(true);
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
+ webview_video.getSettings().setMediaPlaybackRequiresUserGesture(false);
+ }
+ webview_video.setWebViewClient(new MastalabWebViewClient((Activity)context));
+ webview_video.loadUrl(attachment.getUrl());
+ break;
+ case "audio":
+ loader.setVisibility(View.GONE);
+ content_audio.setVisibility(View.VISIBLE);
+ int color = getResources().getColor(R.color.mastodonC1);
+ visualizerView = new GLAudioVisualizationView.Builder(context)
+ .setLayersCount(1)
+ .setWavesCount(6)
+ .setWavesHeight(R.dimen.aar_wave_height)
+ .setWavesFooterHeight(R.dimen.aar_footer_height)
+ .setBubblesPerLayer(20)
+ .setBubblesSize(R.dimen.aar_bubble_size)
+ .setBubblesRandomizeSize(true)
+ .setBackgroundColor(getDarkerColor(color))
+ .setLayerColors(new int[]{color})
+ .build();
+
+ statusView = rootView.findViewById(R.id.status);
+ timerView = rootView.findViewById(R.id.timer);
+ playView = rootView.findViewById(R.id.play);
+ content_audio.setBackgroundColor(getDarkerColor(color));
+ content_audio.addView(visualizerView, 0);
+ playView.setVisibility(View.INVISIBLE);
+ this.url = attachment.getUrl();
+
+ startPlaying();
+ break;
+ }
+ return rootView;
+ }
+
+
+ private void startPlaying() {
+ try {
+
+ playeraudio = new MediaPlayer();
+ playeraudio.setDataSource(url);
+ playeraudio.prepare();
+ playeraudio.start();
+
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+ if (ContextCompat.checkSelfPermission(context, Manifest.permission.RECORD_AUDIO) ==
+ PackageManager.PERMISSION_GRANTED) {
+ visualizerView.linkTo(DbmHandler.Factory.newVisualizerHandler(context, playeraudio));
+ }
+
+ }
+ visualizerView.post(new Runnable() {
+ @Override
+ public void run() {
+ playeraudio.setOnCompletionListener(MediaSliderFragment.this);
+ }
+ });
+
+ timerView.setText("00:00:00");
+ playView.setVisibility(View.VISIBLE);
+ statusView.setText(R.string.aar_playing);
+ statusView.setVisibility(View.VISIBLE);
+ playView.setImageResource(R.drawable.aar_ic_stop);
+
+ playerSecondsElapsed = 0;
+ startTimer();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+
+ private void stopPlaying() {
+ statusView.setText("");
+ statusView.setVisibility(View.INVISIBLE);
+ playView.setImageResource(R.drawable.aar_ic_play);
+
+ visualizerView.release();
+ if (visualizerHandler != null) {
+ visualizerHandler.stop();
+ }
+
+ if (playeraudio != null) {
+ try {
+ playeraudio.pause();
+ } catch (Exception ignored) {
+ }
+ }
+
+ stopTimer();
+ }
+
+ private void startTimer() {
+ stopTimer();
+ timer = new Timer();
+ timer.scheduleAtFixedRate(new TimerTask() {
+ @Override
+ public void run() {
+ updateTimer();
+ }
+ }, 0, 1000);
+ }
+
+ private void updateTimer() {
+ ((Activity)context).runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ playerSecondsElapsed++;
+ timerView.setText(formatSeconds(playerSecondsElapsed));
+ }
+ });
+ }
+
+ private void stopTimer() {
+ if (timer != null) {
+ timer.cancel();
+ timer.purge();
+ timer = null;
+ }
+ }
+
+ private boolean isPlaying() {
+ try {
+ return playeraudio != null && playeraudio.isPlaying();
+ } catch (Exception e) {
+ return false;
+ }
+ }
+
+
+
+ @Override
+ public void onCreate(Bundle saveInstance) {
+ super.onCreate(saveInstance);
+ }
+
+
+
+ @Override
+ public void onAttach(@NotNull Context context) {
+ super.onAttach(context);
+ this.context = context;
+ }
+
+
+ @Override
+ public void onPause() {
+ super.onPause();
+ if (player != null) {
+ player.setPlayWhenReady(false);
+ }
+ if (playeraudio != null) {
+ playeraudio.pause();
+ }
+ try {
+ visualizerView.onPause();
+ } catch (Exception ignored) {
+ }
+ }
+
+ @Override
+ public void onDestroy() {
+ try {
+ if (visualizerView != null) {
+ visualizerView.release();
+ }
+ if (player != null) {
+ player.release();
+ }
+ if (playeraudio != null) {
+ playeraudio.release();
+ }
+ } catch (Exception ignored) {
+ }
+ super.onDestroy();
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ if (player != null) {
+ player.setPlayWhenReady(true);
+ }
+ if (playeraudio != null) {
+ playeraudio.start();
+ }
+ try {
+ visualizerView.onResume();
+ } catch (Exception e) {
+ }
+ }
+
+
+
+ @Override
+ public void onDownloaded(String path, String originUrl, Error error) {
+ if (path != null) {
+ File response = new File(path);
+ File dir = context.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;
+ }
+ if (Build.VERSION.SDK_INT >= 23) {
+ if (ContextCompat.checkSelfPermission(context, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
+ ActivityCompat.requestPermissions((Activity)context, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, Helper.EXTERNAL_STORAGE_REQUEST_CODE);
+ } else {
+ Helper.manageMoveFileDownload(context, preview_url, finalUrlDownload, downloadedImage, fileVideo, isSHaring);
+ }
+ } else {
+ Helper.manageMoveFileDownload(context, preview_url, finalUrlDownload, downloadedImage, fileVideo, isSHaring);
+ }
+ if (progress != null)
+ progress.setVisibility(View.GONE);
+ if (loader != null)
+ loader.setVisibility(View.GONE);
+ }
+
+
+ public boolean canSwipe(){
+ return canSwipe;
+ }
+
+ @Override
+ public void onUpdateProgress(int progressPercentage) {
+ progress.setText(String.format("%s%%", String.valueOf(progressPercentage)));
+ pbar_inf.setProgress(progressPercentage);
+ }
+
+ @Override
+ public void onCompletion(MediaPlayer mp) {
+ stopPlaying();
+ }
+}
diff --git a/app/src/main/res/layout/activity_media_pager.xml b/app/src/main/res/layout/activity_media_pager.xml
new file mode 100644
index 000000000..18d908872
--- /dev/null
+++ b/app/src/main/res/layout/activity_media_pager.xml
@@ -0,0 +1,31 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_slide_media.xml b/app/src/main/res/layout/fragment_slide_media.xml
new file mode 100644
index 000000000..17f29a504
--- /dev/null
+++ b/app/src/main/res/layout/fragment_slide_media.xml
@@ -0,0 +1,256 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file