diff --git a/src/main/AndroidManifest.xml b/src/main/AndroidManifest.xml
index 8388c0157..acea6b555 100644
--- a/src/main/AndroidManifest.xml
+++ b/src/main/AndroidManifest.xml
@@ -380,6 +380,9 @@
+
diff --git a/src/main/java/eu/siacs/conversations/ui/MediaViewerActivity.java b/src/main/java/eu/siacs/conversations/ui/MediaViewerActivity.java
new file mode 100644
index 000000000..c487f91c3
--- /dev/null
+++ b/src/main/java/eu/siacs/conversations/ui/MediaViewerActivity.java
@@ -0,0 +1,142 @@
+package eu.siacs.conversations.ui;
+
+import android.graphics.Color;
+import android.net.Uri;
+import android.os.Bundle;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import androidx.databinding.DataBindingUtil;
+import androidx.viewpager.widget.PagerAdapter;
+import androidx.viewpager.widget.ViewPager;
+import eu.siacs.conversations.R;
+import eu.siacs.conversations.databinding.ActivityMediaViewerBinding;
+import eu.siacs.conversations.entities.Conversation;
+import eu.siacs.conversations.entities.Message;
+import java.util.ArrayList;
+import java.util.List;
+
+public class MediaViewerActivity extends XmppActivity {
+
+ public static final String EXTRA_MESSAGE_UUID =
+ "eu.siacs.conversations.extra.MESSAGE_UUID";
+
+ private ActivityMediaViewerBinding binding;
+ private String conversationUuid;
+ private String messageUuid;
+
+ @Override
+ protected void onCreate(final Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ this.binding =
+ DataBindingUtil.setContentView(this, R.layout.activity_media_viewer);
+ Activities.setStatusAndNavigationBarColors(this, binding.getRoot(), false, false);
+ setSupportActionBar(binding.toolbar);
+ configureActionBar(getSupportActionBar());
+ final var intent = getIntent();
+ if (intent != null) {
+ this.conversationUuid = intent.getStringExtra(ConversationsActivity.EXTRA_CONVERSATION);
+ this.messageUuid = intent.getStringExtra(EXTRA_MESSAGE_UUID);
+ }
+ }
+
+ @Override
+ protected void refreshUiReal() {}
+
+ @Override
+ protected void onBackendConnected() {
+ if (conversationUuid == null) {
+ return;
+ }
+ final Conversation conversation =
+ xmppConnectionService.findConversationByUuidReliable(conversationUuid);
+ if (conversation == null) {
+ return;
+ }
+ final List allMessages = new ArrayList<>();
+ conversation.populateWithMessages(allMessages);
+ final List images = new ArrayList<>();
+ for (final Message message : allMessages) {
+ if (isViewableImage(message)) {
+ images.add(message);
+ }
+ }
+ if (images.isEmpty()) {
+ return;
+ }
+ int startIndex = 0;
+ for (int i = 0; i < images.size(); i++) {
+ if (images.get(i).getUuid().equals(messageUuid)) {
+ startIndex = i;
+ break;
+ }
+ }
+ final int total = images.size();
+ final MediaPagerAdapter adapter = new MediaPagerAdapter(images);
+ binding.mediaPager.setAdapter(adapter);
+ binding.mediaPager.setCurrentItem(startIndex, false);
+ updateTitle(startIndex + 1, total);
+ binding.mediaPager.addOnPageChangeListener(
+ new ViewPager.SimpleOnPageChangeListener() {
+ @Override
+ public void onPageSelected(final int position) {
+ updateTitle(position + 1, total);
+ }
+ });
+ }
+
+ private void updateTitle(final int current, final int total) {
+ setTitle(current + " / " + total);
+ }
+
+ private static boolean isViewableImage(final Message message) {
+ if (!message.isFileOrImage()) {
+ return false;
+ }
+ if (message.getEncryption() == Message.ENCRYPTION_PGP) {
+ return false;
+ }
+ final Message.FileParams params = message.getFileParams();
+ return params.width > 0 && params.height > 0;
+ }
+
+ private class MediaPagerAdapter extends PagerAdapter {
+
+ private final List images;
+
+ MediaPagerAdapter(final List images) {
+ this.images = images;
+ }
+
+ @Override
+ public int getCount() {
+ return images.size();
+ }
+
+ @Override
+ public boolean isViewFromObject(final View view, final Object object) {
+ return view == object;
+ }
+
+ @Override
+ public Object instantiateItem(final ViewGroup container, final int position) {
+ final ImageView imageView = new ImageView(MediaViewerActivity.this);
+ imageView.setScaleType(ImageView.ScaleType.FIT_CENTER);
+ imageView.setBackgroundColor(Color.BLACK);
+ final Message message = images.get(position);
+ final var file =
+ xmppConnectionService.getFileBackend().getFile(message);
+ if (file.exists()) {
+ imageView.setImageURI(Uri.fromFile(file));
+ }
+ container.addView(imageView);
+ return imageView;
+ }
+
+ @Override
+ public void destroyItem(
+ final ViewGroup container, final int position, final Object object) {
+ container.removeView((View) object);
+ }
+ }
+}
diff --git a/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java b/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java
index 97828bbf9..d3d864c7c 100644
--- a/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java
+++ b/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java
@@ -69,6 +69,7 @@
import eu.siacs.conversations.ui.BindingAdapters;
import eu.siacs.conversations.ui.ConversationFragment;
import eu.siacs.conversations.ui.ConversationsActivity;
+import eu.siacs.conversations.ui.MediaViewerActivity;
import eu.siacs.conversations.ui.XmppActivity;
import eu.siacs.conversations.ui.service.AudioPlayer;
import eu.siacs.conversations.ui.text.DividerSpan;
@@ -688,7 +689,7 @@ private void displayMediaPreviewMessage(
new LinearLayout.LayoutParams(scaledW, scaledH);
viewHolder.image().setLayoutParams(layoutParams);
activity.loadBitmap(message, viewHolder.image());
- viewHolder.image().setOnClickListener(v -> openDownloadable(message));
+ viewHolder.image().setOnClickListener(v -> openMediaViewer(message));
}
private void toggleWhisperInfo(
@@ -1352,6 +1353,13 @@ public void openDownloadable(Message message) {
ViewUtil.view(activity, file);
}
+ private void openMediaViewer(final Message message) {
+ final Intent intent = new Intent(activity, MediaViewerActivity.class);
+ intent.putExtra(ConversationsActivity.EXTRA_CONVERSATION, message.getConversationUuid());
+ intent.putExtra(MediaViewerActivity.EXTRA_MESSAGE_UUID, message.getUuid());
+ activity.startActivity(intent);
+ }
+
private void showLocation(Message message) {
for (Intent intent : GeoHelper.createGeoIntentsFromMessage(activity, message)) {
if (intent.resolveActivity(getContext().getPackageManager()) != null) {
diff --git a/src/main/res/layout/activity_media_viewer.xml b/src/main/res/layout/activity_media_viewer.xml
new file mode 100644
index 000000000..9fa601ed4
--- /dev/null
+++ b/src/main/res/layout/activity_media_viewer.xml
@@ -0,0 +1,29 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+