diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 4b08467b7..b68621ffb 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -495,10 +495,12 @@
android:windowSoftInputMode="stateHidden"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
-
-
-
diff --git a/app/src/main/java/org/thoughtcrime/securesms/MediaPreviewActivity.java b/app/src/main/java/org/thoughtcrime/securesms/MediaPreviewActivity.java
deleted file mode 100644
index a1d6a2289..000000000
--- a/app/src/main/java/org/thoughtcrime/securesms/MediaPreviewActivity.java
+++ /dev/null
@@ -1,869 +0,0 @@
-/*
- * Copyright (C) 2014 Open Whisper Systems
- *
- * 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.
- *
- * This program 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-package org.thoughtcrime.securesms;
-
-import android.Manifest;
-import android.annotation.SuppressLint;
-import android.content.ActivityNotFoundException;
-import android.content.Context;
-import android.content.Intent;
-import android.database.Cursor;
-import android.net.Uri;
-import android.os.AsyncTask;
-import android.os.Bundle;
-import android.view.Menu;
-import android.view.MenuInflater;
-import android.view.MenuItem;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.TextView;
-import android.widget.Toast;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.appcompat.app.AlertDialog;
-import androidx.appcompat.app.AppCompatDelegate;
-import androidx.core.app.ShareCompat;
-import androidx.core.util.Pair;
-import androidx.core.view.ViewCompat;
-import androidx.fragment.app.Fragment;
-import androidx.fragment.app.FragmentManager;
-import androidx.fragment.app.FragmentStatePagerAdapter;
-import androidx.lifecycle.ViewModelProvider;
-import androidx.loader.app.LoaderManager;
-import androidx.loader.content.Loader;
-import androidx.recyclerview.widget.LinearLayoutManager;
-import androidx.recyclerview.widget.RecyclerView;
-import androidx.viewpager.widget.ViewPager;
-
-import com.google.android.material.dialog.MaterialAlertDialogBuilder;
-
-import org.signal.core.util.logging.Log;
-import org.thoughtcrime.securesms.animation.DepthPageTransformer;
-import org.thoughtcrime.securesms.attachments.DatabaseAttachment;
-import org.thoughtcrime.securesms.components.viewpager.ExtendedOnPageChangedListener;
-import org.thoughtcrime.securesms.components.voice.VoiceNoteMediaController;
-import org.thoughtcrime.securesms.components.voice.VoiceNoteMediaControllerOwner;
-import org.thoughtcrime.securesms.conversation.mutiselect.forward.MultiselectForwardFragment;
-import org.thoughtcrime.securesms.conversation.mutiselect.forward.MultiselectForwardFragmentArgs;
-import org.thoughtcrime.securesms.database.MediaDatabase;
-import org.thoughtcrime.securesms.database.MediaDatabase.MediaRecord;
-import org.thoughtcrime.securesms.database.loaders.PagingMediaLoader;
-import org.thoughtcrime.securesms.mediaoverview.MediaOverviewActivity;
-import org.thoughtcrime.securesms.mediapreview.MediaIntentFactory;
-import org.thoughtcrime.securesms.mediapreview.MediaPreviewFragment;
-import org.thoughtcrime.securesms.mediapreview.MediaPreviewViewModel;
-import org.thoughtcrime.securesms.mediapreview.MediaRailAdapter;
-import org.thoughtcrime.securesms.mms.GlideApp;
-import org.thoughtcrime.securesms.mms.PartAuthority;
-import org.thoughtcrime.securesms.permissions.Permissions;
-import org.thoughtcrime.securesms.recipients.Recipient;
-import org.thoughtcrime.securesms.recipients.RecipientId;
-import org.thoughtcrime.securesms.util.AttachmentUtil;
-import org.thoughtcrime.securesms.util.DateUtils;
-import org.thoughtcrime.securesms.util.FullscreenHelper;
-import org.thoughtcrime.securesms.util.MediaUtil;
-import org.thoughtcrime.securesms.util.SaveAttachmentTask;
-import org.thoughtcrime.securesms.util.SaveAttachmentTask.Attachment;
-import org.thoughtcrime.securesms.util.StorageUtil;
-
-import java.util.HashMap;
-import java.util.Locale;
-import java.util.Map;
-import java.util.Objects;
-
-/**
- * Activity for displaying media attachments in-app
- */
-public final class MediaPreviewActivity extends PassphraseRequiredActivity
- implements LoaderManager.LoaderCallbacks>,
- MediaRailAdapter.RailItemListener,
- MediaPreviewFragment.Events,
- VoiceNoteMediaControllerOwner
-{
-
- private final static String TAG = Log.tag(MediaPreviewActivity.class);
-
- private ViewPager mediaPager;
- private View detailsContainer;
- private TextView caption;
- private View captionContainer;
- private RecyclerView albumRail;
- private MediaRailAdapter albumRailAdapter;
- private ViewGroup playbackControlsContainer;
- private Uri initialMediaUri;
- private String initialMediaType;
- private long initialMediaSize;
- private String initialCaption;
- private boolean initialMediaIsVideoGif;
- private boolean leftIsRecent;
- private MediaPreviewViewModel viewModel;
- private ViewPagerListener viewPagerListener;
-
- private int restartItem = -1;
- private long threadId = MediaIntentFactory.NOT_IN_A_THREAD;
- private boolean cameFromAllMedia;
- private boolean showThread;
- private MediaDatabase.Sorting sorting;
- private FullscreenHelper fullscreenHelper;
-
- private VoiceNoteMediaController voiceNoteMediaController;
-
- private @Nullable Cursor cursor = null;
-
- public static @NonNull Intent intentFromMediaRecord(@NonNull Context context,
- @NonNull MediaRecord mediaRecord,
- boolean leftIsRecent)
- {
- DatabaseAttachment attachment = Objects.requireNonNull(mediaRecord.getAttachment());
- Intent intent = new Intent(context, MediaPreviewActivity.class);
- intent.putExtra(MediaIntentFactory.THREAD_ID_EXTRA, mediaRecord.getThreadId());
- intent.putExtra(MediaIntentFactory.DATE_EXTRA, mediaRecord.getDate());
- intent.putExtra(MediaIntentFactory.SIZE_EXTRA, attachment.getSize());
- intent.putExtra(MediaIntentFactory.CAPTION_EXTRA, attachment.getCaption());
- intent.putExtra(MediaIntentFactory.LEFT_IS_RECENT_EXTRA, leftIsRecent);
- intent.putExtra(MediaIntentFactory.IS_VIDEO_GIF, attachment.isVideoGif());
- intent.setDataAndType(attachment.getUri(), mediaRecord.getContentType());
- return intent;
- }
-
- @Override
- protected void attachBaseContext(@NonNull Context newBase) {
- getDelegate().setLocalNightMode(AppCompatDelegate.MODE_NIGHT_YES);
- super.attachBaseContext(newBase);
- }
-
- @SuppressWarnings("ConstantConditions")
- @Override
- protected void onCreate(Bundle bundle, boolean ready) {
- this.setTheme(R.style.TextSecure_MediaPreview);
- setContentView(R.layout.media_preview_activity);
-
- setSupportActionBar(findViewById(R.id.toolbar));
-
- voiceNoteMediaController = new VoiceNoteMediaController(this);
- viewModel = new ViewModelProvider(this).get(MediaPreviewViewModel.class);
-
- fullscreenHelper = new FullscreenHelper(this);
-
- getSupportActionBar().setDisplayHomeAsUpEnabled(true);
-
- initializeViews();
- initializeResources();
- initializeObservers();
- }
-
- @SuppressLint("MissingSuperCall")
- @Override
- public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
- Permissions.onRequestPermissionsResult(this, requestCode, permissions, grantResults);
- }
-
- @Override
- public void onRailItemClicked(int distanceFromActive) {
- mediaPager.setCurrentItem(mediaPager.getCurrentItem() + distanceFromActive);
- }
-
- @Override
- public void onRailItemDeleteClicked(int distanceFromActive) {
- throw new UnsupportedOperationException("Callback unsupported.");
- }
-
- @SuppressWarnings("ConstantConditions")
- private void initializeActionBar() {
- MediaItem mediaItem = getCurrentMediaItem();
-
- if (mediaItem != null) {
- getSupportActionBar().setTitle(getTitleText(mediaItem));
- getSupportActionBar().setSubtitle(getSubTitleText(mediaItem));
- }
- }
-
- private @NonNull String getTitleText(@NonNull MediaItem mediaItem) {
- String from;
- if (mediaItem.outgoing) from = getString(R.string.MediaPreviewActivity_you);
- else if (mediaItem.recipient != null) from = mediaItem.recipient.getDisplayName(this);
- else from = "";
-
- if (showThread) {
- String titleText = null;
- Recipient threadRecipient = mediaItem.threadRecipient;
-
- if (threadRecipient != null) {
- if (mediaItem.outgoing) {
- if (threadRecipient.isSelf()) {
- titleText = getString(R.string.note_to_self);
- } else {
- titleText = getString(R.string.MediaPreviewActivity_you_to_s, threadRecipient.getDisplayName(this));
- }
- } else {
- if (threadRecipient.isGroup()) {
- titleText = getString(R.string.MediaPreviewActivity_s_to_s, from, threadRecipient.getDisplayName(this));
- } else {
- titleText = getString(R.string.MediaPreviewActivity_s_to_you, from);
- }
- }
- }
- return titleText != null ? titleText : from;
- } else {
- return from;
- }
- }
-
- private @NonNull String getSubTitleText(@NonNull MediaItem mediaItem) {
- if (mediaItem.date > 0) {
- return DateUtils.getExtendedRelativeTimeSpanString(this, Locale.getDefault(), mediaItem.date);
- } else {
- return getString(R.string.MediaPreviewActivity_draft);
- }
- }
-
- @Override
- public void onResume() {
- super.onResume();
-
- initializeMedia();
- }
-
- @Override
- public void onPause() {
- super.onPause();
- restartItem = cleanupMedia();
- }
-
- @Override
- protected void onDestroy() {
- if (cursor != null) {
- cursor.close();
- cursor = null;
- }
- super.onDestroy();
- }
-
- @Override
- protected void onNewIntent(Intent intent) {
- super.onNewIntent(intent);
- setIntent(intent);
- initializeResources();
- }
-
- private void initializeViews() {
- mediaPager = findViewById(R.id.media_pager);
- mediaPager.setOffscreenPageLimit(1);
- mediaPager.setPageTransformer(true, new DepthPageTransformer());
-
- viewPagerListener = new ViewPagerListener();
- mediaPager.addOnPageChangeListener(viewPagerListener);
-
- albumRail = findViewById(R.id.media_preview_album_rail);
- albumRailAdapter = new MediaRailAdapter(GlideApp.with(this), this, false);
-
- albumRail.setItemAnimator(null); // Or can crash when set to INVISIBLE while animating by FullscreenHelper https://issuetracker.google.com/issues/148720682
- albumRail.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false));
- albumRail.setAdapter(albumRailAdapter);
-
- detailsContainer = findViewById(R.id.media_preview_details_container);
- caption = findViewById(R.id.media_preview_caption);
- captionContainer = findViewById(R.id.media_preview_caption_container);
- playbackControlsContainer = findViewById(R.id.media_preview_playback_controls_container);
-
- View toolbarLayout = findViewById(R.id.toolbar_layout);
-
- anchorMarginsToBottomInsets(detailsContainer);
-
- fullscreenHelper.configureToolbarLayout(findViewById(R.id.toolbar_cutout_spacer), findViewById(R.id.toolbar));
-
- fullscreenHelper.showAndHideWithSystemUI(getWindow(), detailsContainer, toolbarLayout);
- }
-
- private void initializeResources() {
- Intent intent = getIntent();
-
- threadId = intent.getLongExtra(MediaIntentFactory.THREAD_ID_EXTRA, MediaIntentFactory.NOT_IN_A_THREAD);
- cameFromAllMedia = intent.getBooleanExtra(MediaIntentFactory.HIDE_ALL_MEDIA_EXTRA, false);
- showThread = intent.getBooleanExtra(MediaIntentFactory.SHOW_THREAD_EXTRA, false);
- sorting = MediaDatabase.Sorting.values()[intent.getIntExtra(MediaIntentFactory.SORTING_EXTRA, 0)];
-
- initialMediaUri = intent.getData();
- initialMediaType = intent.getType();
- initialMediaSize = intent.getLongExtra(MediaIntentFactory.SIZE_EXTRA, 0);
- initialCaption = intent.getStringExtra(MediaIntentFactory.CAPTION_EXTRA);
- leftIsRecent = intent.getBooleanExtra(MediaIntentFactory.LEFT_IS_RECENT_EXTRA, false);
- initialMediaIsVideoGif = intent.getBooleanExtra(MediaIntentFactory.IS_VIDEO_GIF, false);
- restartItem = -1;
- }
-
- private void initializeObservers() {
- viewModel.getPreviewData().observe(this, previewData -> {
- if (previewData == null || mediaPager == null || mediaPager.getAdapter() == null) {
- return;
- }
-
- if (!((MediaItemAdapter) mediaPager.getAdapter()).hasFragmentFor(mediaPager.getCurrentItem())) {
- Log.d(TAG, "MediaItemAdapter wasn't ready. Posting again...");
- viewModel.resubmitPreviewData();
- }
-
- View playbackControls = ((MediaItemAdapter) mediaPager.getAdapter()).getPlaybackControls(mediaPager.getCurrentItem());
-
- if (previewData.getAlbumThumbnails().isEmpty() && previewData.getCaption() == null && playbackControls == null) {
- detailsContainer.setVisibility(View.GONE);
- } else {
- detailsContainer.setVisibility(View.VISIBLE);
- }
-
- albumRail.setVisibility(previewData.getAlbumThumbnails().isEmpty() ? View.GONE : View.VISIBLE);
- albumRailAdapter.setMedia(previewData.getAlbumThumbnails(), previewData.getActivePosition());
- albumRail.smoothScrollToPosition(previewData.getActivePosition());
-
- captionContainer.setVisibility(previewData.getCaption() == null ? View.GONE : View.VISIBLE);
- caption.setText(previewData.getCaption());
-
- if (playbackControls != null) {
- ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
- playbackControls.setLayoutParams(params);
-
- playbackControlsContainer.removeAllViews();
- playbackControlsContainer.addView(playbackControls);
- } else {
- playbackControlsContainer.removeAllViews();
- }
- });
- }
-
- private void initializeMedia() {
- if (!isContentTypeSupported(initialMediaType)) {
- Log.w(TAG, "Unsupported media type sent to MediaPreviewActivity, finishing.");
- Toast.makeText(getApplicationContext(), R.string.MediaPreviewActivity_unssuported_media_type, Toast.LENGTH_LONG).show();
- finish();
- }
-
- Log.i(TAG, "Loading Part URI: " + initialMediaUri);
-
- if (isMediaInDb()) {
- LoaderManager.getInstance(this).restartLoader(0, null, this);
- } else {
- mediaPager.setAdapter(new SingleItemPagerAdapter(getSupportFragmentManager(), initialMediaUri, initialMediaType, initialMediaSize, initialMediaIsVideoGif));
-
- if (initialCaption != null) {
- detailsContainer.setVisibility(View.VISIBLE);
- captionContainer.setVisibility(View.VISIBLE);
- caption.setText(initialCaption);
- }
- }
- }
-
- private int cleanupMedia() {
- int restartItem = mediaPager.getCurrentItem();
-
- mediaPager.removeAllViews();
- mediaPager.setAdapter(null);
- viewModel.setCursor(this, null, leftIsRecent);
-
- return restartItem;
- }
-
- private void showOverview() {
- startActivity(MediaOverviewActivity.forThread(this, threadId));
- }
-
- private void forward() {
- MediaItem mediaItem = getCurrentMediaItem();
-
- if (mediaItem != null) {
- MultiselectForwardFragmentArgs.create(
- this,
- threadId,
- mediaItem.uri,
- mediaItem.type,
- args -> MultiselectForwardFragment.showBottomSheet(getSupportFragmentManager(), args)
- );
- }
- }
-
- private void share() {
- MediaItem mediaItem = getCurrentMediaItem();
-
- if (mediaItem != null) {
- Uri publicUri = PartAuthority.getAttachmentPublicUri(mediaItem.uri);
- String mimeType = Intent.normalizeMimeType(mediaItem.type);
- Intent shareIntent = ShareCompat.IntentBuilder.from(this)
- .setStream(publicUri)
- .setType(mimeType)
- .createChooserIntent()
- .addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
-
- try {
- startActivity(shareIntent);
- } catch (ActivityNotFoundException e) {
- Log.w(TAG, "No activity existed to share the media.", e);
- Toast.makeText(this, R.string.MediaPreviewActivity_cant_find_an_app_able_to_share_this_media, Toast.LENGTH_LONG).show();
- }
- }
- }
-
- @SuppressWarnings("CodeBlock2Expr")
- @SuppressLint("InlinedApi")
- private void saveToDisk() {
- MediaItem mediaItem = getCurrentMediaItem();
-
- if (mediaItem != null) {
- SaveAttachmentTask.showWarningDialog(this, (dialogInterface, i) -> {
- if (StorageUtil.canWriteToMediaStore()) {
- performSavetoDisk(mediaItem);
- return;
- }
-
- Permissions.with(this)
- .request(Manifest.permission.WRITE_EXTERNAL_STORAGE)
- .ifNecessary()
- .withPermanentDenialDialog(getString(R.string.MediaPreviewActivity_signal_needs_the_storage_permission_in_order_to_write_to_external_storage_but_it_has_been_permanently_denied))
- .onAnyDenied(() -> Toast.makeText(this, R.string.MediaPreviewActivity_unable_to_write_to_external_storage_without_permission, Toast.LENGTH_LONG).show())
- .onAllGranted(() -> {
- performSavetoDisk(mediaItem);
- })
- .execute();
- });
- }
- }
-
- private void performSavetoDisk(@NonNull MediaItem mediaItem) {
- SaveAttachmentTask saveTask = new SaveAttachmentTask(MediaPreviewActivity.this);
- long saveDate = (mediaItem.date > 0) ? mediaItem.date : System.currentTimeMillis();
- saveTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, new Attachment(mediaItem.uri, mediaItem.type, saveDate, null));
- }
-
- @SuppressLint("StaticFieldLeak")
- private void deleteMedia() {
- MediaItem mediaItem = getCurrentMediaItem();
- if (mediaItem == null || mediaItem.attachment == null) {
- return;
- }
-
- AlertDialog.Builder builder = new MaterialAlertDialogBuilder(this);
- builder.setIcon(R.drawable.ic_warning);
- builder.setTitle(R.string.MediaPreviewActivity_media_delete_confirmation_title);
- builder.setMessage(R.string.MediaPreviewActivity_media_delete_confirmation_message);
- builder.setCancelable(true);
-
- builder.setPositiveButton(R.string.delete, (dialogInterface, which) -> {
- new AsyncTask() {
- @Override
- protected Void doInBackground(Void... voids) {
- AttachmentUtil.deleteAttachment(MediaPreviewActivity.this.getApplicationContext(),
- mediaItem.attachment);
- return null;
- }
- }.execute();
-
- finish();
- });
- builder.setNegativeButton(android.R.string.cancel, null);
- builder.show();
- }
-
- @Override
- public boolean onCreateOptionsMenu(Menu menu) {
- menu.clear();
- MenuInflater inflater = this.getMenuInflater();
- inflater.inflate(R.menu.media_preview, menu);
-
- super.onCreateOptionsMenu(menu);
- return true;
- }
-
- @Override
- public boolean onPrepareOptionsMenu(Menu menu) {
- if (!isMediaInDb()) {
- menu.findItem(R.id.delete).setVisible(false);
- }
- super.onPrepareOptionsMenu(menu);
- return true;
- }
-
- @Override
- public boolean onOptionsItemSelected(@NonNull MenuItem item) {
- super.onOptionsItemSelected(item);
-
- int itemId = item.getItemId();
-
- if (itemId == R.id.save) { saveToDisk(); return true; }
- if (itemId == R.id.delete) { deleteMedia(); return true; }
- if (itemId == android.R.id.home) { finish(); return true; }
-
- return false;
- }
-
- private boolean isMediaInDb() {
- return threadId != MediaIntentFactory.NOT_IN_A_THREAD;
- }
-
- private @Nullable MediaItem getCurrentMediaItem() {
- MediaItemAdapter adapter = (MediaItemAdapter)mediaPager.getAdapter();
-
- if (adapter != null) {
- return adapter.getMediaItemFor(mediaPager.getCurrentItem());
- } else {
- return null;
- }
- }
-
- public static boolean isContentTypeSupported(final String contentType) {
- return MediaUtil.isImageType(contentType) || MediaUtil.isVideoType(contentType);
- }
-
- @Override
- public @NonNull Loader> onCreateLoader(int id, Bundle args) {
- return new PagingMediaLoader(this, threadId, initialMediaUri, leftIsRecent, sorting);
- }
-
- @Override
- public void onLoadFinished(@NonNull Loader> loader, @Nullable Pair data) {
- if (data != null) {
- if (data.first == cursor) {
- return;
- }
-
- if (cursor != null) {
- cursor.close();
- }
- cursor = Objects.requireNonNull(data.first);
-
- viewModel.setCursor(this, cursor, leftIsRecent);
-
- int mediaPosition = Objects.requireNonNull(data.second);
-
- CursorPagerAdapter oldAdapter = (CursorPagerAdapter) mediaPager.getAdapter();
- if (oldAdapter == null) {
- CursorPagerAdapter adapter = new CursorPagerAdapter(getSupportFragmentManager(), this, cursor, mediaPosition, leftIsRecent);
- mediaPager.setAdapter(adapter);
- adapter.setActive(true);
- } else {
- oldAdapter.setCursor(cursor, mediaPosition);
- oldAdapter.setActive(true);
- }
-
- if (oldAdapter == null || restartItem >= 0) {
- int item = restartItem >= 0 ? restartItem : mediaPosition;
- mediaPager.setCurrentItem(item);
-
- if (item == 0) {
- viewPagerListener.onPageSelected(0);
- }
- }
- } else {
- onMediaNotAvailable();
- }
- }
-
- @Override
- public void onLoaderReset(@NonNull Loader> loader) {
-
- }
-
- @Override
- public boolean singleTapOnMedia() {
- fullscreenHelper.toggleUiVisibility();
- return true;
- }
-
- @Override
- public void onMediaNotAvailable() {
- Toast.makeText(this, R.string.MediaPreviewActivity_media_no_longer_available, Toast.LENGTH_LONG).show();
- finish();
- }
-
- @Override
- public void onMediaReady() {
- }
-
- @Override
- public @NonNull VoiceNoteMediaController getVoiceNoteMediaController() {
- return voiceNoteMediaController;
- }
-
- private class ViewPagerListener extends ExtendedOnPageChangedListener {
-
- @Override
- public void onPageSelected(int position) {
- super.onPageSelected(position);
-
- MediaItemAdapter adapter = (MediaItemAdapter)mediaPager.getAdapter();
-
- if (adapter != null) {
- MediaItem item = adapter.getMediaItemFor(position);
- if (item != null && item.recipient != null) {
- item.recipient.live().observe(MediaPreviewActivity.this, r -> initializeActionBar());
- }
-
- viewModel.setActiveAlbumRailItem(MediaPreviewActivity.this, position);
- initializeActionBar();
- }
- }
-
-
- @Override
- public void onPageUnselected(int position) {
- MediaItemAdapter adapter = (MediaItemAdapter)mediaPager.getAdapter();
-
- if (adapter != null) {
- MediaItem item = adapter.getMediaItemFor(position);
- if (item != null && item.recipient != null) {
- item.recipient.live().removeObservers(MediaPreviewActivity.this);
- }
-
- adapter.pause(position);
- }
- }
- }
-
- private static class SingleItemPagerAdapter extends FragmentStatePagerAdapter implements MediaItemAdapter {
-
- private final Uri uri;
- private final String mediaType;
- private final long size;
- private final boolean isVideoGif;
-
- private MediaPreviewFragment mediaPreviewFragment;
-
- SingleItemPagerAdapter(@NonNull FragmentManager fragmentManager,
- @NonNull Uri uri,
- @NonNull String mediaType,
- long size,
- boolean isVideoGif)
- {
- super(fragmentManager, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT);
- this.uri = uri;
- this.mediaType = mediaType;
- this.size = size;
- this.isVideoGif = isVideoGif;
- }
-
- @Override
- public int getCount() {
- return 1;
- }
-
- @NonNull
- @Override
- public Fragment getItem(int position) {
- mediaPreviewFragment = MediaPreviewFragment.newInstance(uri, mediaType, size, true, isVideoGif);
- return mediaPreviewFragment;
- }
-
- @Override
- public void destroyItem(@NonNull ViewGroup container, int position, @NonNull Object object) {
- if (mediaPreviewFragment != null) {
- mediaPreviewFragment.cleanUp();
- mediaPreviewFragment = null;
- }
- }
-
- @Override
- public @Nullable MediaItem getMediaItemFor(int position) {
- return new MediaItem(null, null, null, uri, mediaType, -1, true);
- }
-
- @Override
- public void pause(int position) {
- if (mediaPreviewFragment != null) {
- mediaPreviewFragment.pause();
- }
- }
-
- @Override
- public @Nullable View getPlaybackControls(int position) {
- if (mediaPreviewFragment != null) {
- return mediaPreviewFragment.getBottomBarControls();
- }
- return null;
- }
-
- @Override
- public boolean hasFragmentFor(int position) {
- return mediaPreviewFragment != null;
- }
- }
-
- private static void anchorMarginsToBottomInsets(@NonNull View viewToAnchor) {
- ViewCompat.setOnApplyWindowInsetsListener(viewToAnchor, (view, insets) -> {
- ViewGroup.MarginLayoutParams layoutParams = (ViewGroup.MarginLayoutParams) view.getLayoutParams();
-
- layoutParams.setMargins(insets.getSystemWindowInsetLeft(),
- layoutParams.topMargin,
- insets.getSystemWindowInsetRight(),
- insets.getSystemWindowInsetBottom());
-
- view.setLayoutParams(layoutParams);
-
- return insets;
- });
- }
-
- private static class CursorPagerAdapter extends FragmentStatePagerAdapter implements MediaItemAdapter {
-
- @SuppressLint("UseSparseArrays")
- private final Map mediaFragments = new HashMap<>();
-
- private final Context context;
- private final boolean leftIsRecent;
-
- private boolean active;
- private Cursor cursor;
- private int autoPlayPosition;
-
- CursorPagerAdapter(@NonNull FragmentManager fragmentManager,
- @NonNull Context context,
- @NonNull Cursor cursor,
- int autoPlayPosition,
- boolean leftIsRecent)
- {
- super(fragmentManager, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT);
- this.context = context.getApplicationContext();
- this.cursor = cursor;
- this.autoPlayPosition = autoPlayPosition;
- this.leftIsRecent = leftIsRecent;
- }
-
- public void setActive(boolean active) {
- this.active = active;
- notifyDataSetChanged();
- }
-
- public void setCursor(@NonNull Cursor cursor, int autoPlayPosition) {
- this.cursor = cursor;
- this.autoPlayPosition = autoPlayPosition;
- }
-
- @Override
- public int getCount() {
- if (!active) return 0;
- else return cursor.getCount();
- }
-
- @NonNull
- @Override
- public Fragment getItem(int position) {
- boolean autoPlay = autoPlayPosition == position;
- int cursorPosition = getCursorPosition(position);
-
- autoPlayPosition = -1;
-
- cursor.moveToPosition(cursorPosition);
-
- MediaDatabase.MediaRecord mediaRecord = MediaDatabase.MediaRecord.from(cursor);
- DatabaseAttachment attachment = Objects.requireNonNull(mediaRecord.getAttachment());
- MediaPreviewFragment fragment = MediaPreviewFragment.newInstance(attachment, autoPlay);
-
- mediaFragments.put(position, fragment);
-
- return fragment;
- }
-
- @Override
- public void destroyItem(@NonNull ViewGroup container, int position, @NonNull Object object) {
- MediaPreviewFragment removed = mediaFragments.remove(position);
-
- if (removed != null) {
- removed.cleanUp();
- }
-
- super.destroyItem(container, position, object);
- }
-
- public @Nullable MediaItem getMediaItemFor(int position) {
- int cursorPosition = getCursorPosition(position);
-
- if (cursor.isClosed() || cursorPosition < 0) {
- Log.w(TAG, "Invalid cursor state! Closed: " + cursor.isClosed() + " Position: " + cursorPosition);
- return null;
- }
-
- cursor.moveToPosition(cursorPosition);
-
- MediaRecord mediaRecord = MediaRecord.from(cursor);
- DatabaseAttachment attachment = Objects.requireNonNull(mediaRecord.getAttachment());
- RecipientId recipientId = mediaRecord.getRecipientId();
- RecipientId threadRecipientId = mediaRecord.getThreadRecipientId();
-
- return new MediaItem(Recipient.live(recipientId).get(),
- Recipient.live(threadRecipientId).get(),
- attachment,
- Objects.requireNonNull(attachment.getUri()),
- mediaRecord.getContentType(),
- mediaRecord.getDate(),
- mediaRecord.isOutgoing());
- }
-
- @Override
- public void pause(int position) {
- MediaPreviewFragment mediaView = mediaFragments.get(position);
- if (mediaView != null) mediaView.pause();
- }
-
- @Override
- public @Nullable View getPlaybackControls(int position) {
- MediaPreviewFragment mediaView = mediaFragments.get(position);
- if (mediaView != null) return mediaView.getBottomBarControls();
- return null;
- }
-
- @Override
- public boolean hasFragmentFor(int position) {
- return mediaFragments.containsKey(position);
- }
-
- private int getCursorPosition(int position) {
- if (leftIsRecent) return position;
- else return cursor.getCount() - 1 - position;
- }
- }
-
- private static class MediaItem {
- private final @Nullable Recipient recipient;
- private final @Nullable Recipient threadRecipient;
- private final @Nullable DatabaseAttachment attachment;
- private final @NonNull Uri uri;
- private final @NonNull String type;
- private final long date;
- private final boolean outgoing;
-
- private MediaItem(@Nullable Recipient recipient,
- @Nullable Recipient threadRecipient,
- @Nullable DatabaseAttachment attachment,
- @NonNull Uri uri,
- @NonNull String type,
- long date,
- boolean outgoing)
- {
- this.recipient = recipient;
- this.threadRecipient = threadRecipient;
- this.attachment = attachment;
- this.uri = uri;
- this.type = type;
- this.date = date;
- this.outgoing = outgoing;
- }
- }
-
- interface MediaItemAdapter {
- @Nullable MediaItem getMediaItemFor(int position);
- void pause(int position);
- @Nullable View getPlaybackControls(int position);
- boolean hasFragmentFor(int position);
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/settings/conversation/ConversationSettingsFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/components/settings/conversation/ConversationSettingsFragment.kt
index 924240e1e..14e71ef18 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/components/settings/conversation/ConversationSettingsFragment.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/components/settings/conversation/ConversationSettingsFragment.kt
@@ -28,7 +28,6 @@ import org.signal.core.util.DimensionUnit
import org.thoughtcrime.securesms.AvatarPreviewActivity
import org.thoughtcrime.securesms.BlockUnblockDialog
import org.thoughtcrime.securesms.InviteActivity
-import org.thoughtcrime.securesms.MediaPreviewActivity
import org.thoughtcrime.securesms.MuteDialog
import org.thoughtcrime.securesms.PushContactSelectionActivity
import org.thoughtcrime.securesms.R
@@ -69,6 +68,7 @@ import org.thoughtcrime.securesms.groups.ui.managegroup.dialogs.GroupInviteSentD
import org.thoughtcrime.securesms.groups.ui.managegroup.dialogs.GroupsLearnMoreBottomSheetDialogFragment
import org.thoughtcrime.securesms.groups.ui.migration.GroupsV1MigrationInitiationBottomSheetDialogFragment
import org.thoughtcrime.securesms.mediaoverview.MediaOverviewActivity
+import org.thoughtcrime.securesms.mediapreview.MediaIntentFactory
import org.thoughtcrime.securesms.profiles.edit.EditProfileActivity
import org.thoughtcrime.securesms.recipients.Recipient
import org.thoughtcrime.securesms.recipients.RecipientExporter
@@ -513,7 +513,7 @@ class ConversationSettingsFragment : DSLSettingsFragment(
mediaIds = state.sharedMediaIds,
onMediaRecordClick = { mediaRecord, isLtr ->
startActivityForResult(
- MediaPreviewActivity.intentFromMediaRecord(requireContext(), mediaRecord, isLtr),
+ MediaIntentFactory.intentFromMediaRecord(requireContext(), mediaRecord, isLtr),
REQUEST_CODE_RETURN_FROM_MEDIA
)
}
diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationItem.java b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationItem.java
index df9218c4d..f7f279941 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationItem.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationItem.java
@@ -71,7 +71,6 @@ import org.signal.core.util.DimensionUnit;
import org.signal.core.util.StringUtil;
import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.BindableConversationItem;
-import org.thoughtcrime.securesms.MediaPreviewActivity;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.attachments.DatabaseAttachment;
import org.thoughtcrime.securesms.badges.BadgeImageView;
@@ -114,6 +113,7 @@ import org.thoughtcrime.securesms.jobs.SmsSendJob;
import org.thoughtcrime.securesms.keyvalue.SignalStore;
import org.thoughtcrime.securesms.linkpreview.LinkPreview;
import org.thoughtcrime.securesms.mediapreview.MediaIntentFactory;
+import org.thoughtcrime.securesms.mediapreview.MediaPreviewV2Fragment;
import org.thoughtcrime.securesms.mms.GlideRequests;
import org.thoughtcrime.securesms.mms.ImageSlide;
import org.thoughtcrime.securesms.mms.PartAuthority;
@@ -2321,7 +2321,7 @@ public final class ConversationItem extends RelativeLayout implements BindableCo
performClick();
} else if (!canPlayContent && mediaItem != null && eventListener != null) {
eventListener.onPlayInlineContent(conversationMessage);
- } else if (MediaPreviewActivity.isContentTypeSupported(slide.getContentType()) && slide.getUri() != null) {
+ } else if (MediaPreviewV2Fragment.isContentTypeSupported(slide.getContentType()) && slide.getUri() != null) {
MediaIntentFactory.MediaPreviewArgs args = new MediaIntentFactory.MediaPreviewArgs(
messageRecord.getThreadId(),
messageRecord.getTimestamp(),
@@ -2333,7 +2333,7 @@ public final class ConversationItem extends RelativeLayout implements BindableCo
false,
false,
false,
- MediaDatabase.Sorting.Newest.ordinal(),
+ MediaDatabase.Sorting.Newest,
slide.isVideoGif());
context.startActivity(MediaIntentFactory.create(context, args));
} else if (slide.getUri() != null) {
diff --git a/app/src/main/java/org/thoughtcrime/securesms/mediaoverview/MediaOverviewPageFragment.java b/app/src/main/java/org/thoughtcrime/securesms/mediaoverview/MediaOverviewPageFragment.java
index e9c07a734..39e7e30f0 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/mediaoverview/MediaOverviewPageFragment.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/mediaoverview/MediaOverviewPageFragment.java
@@ -248,7 +248,7 @@ public final class MediaOverviewPageFragment extends Fragment
true,
threadId == MediaDatabase.ALL_THREADS,
true,
- sorting.ordinal(),
+ sorting,
attachment.isVideoGif());
context.startActivity(MediaIntentFactory.create(context, args));
} else {
diff --git a/app/src/main/java/org/thoughtcrime/securesms/mediapreview/MediaIntentFactory.kt b/app/src/main/java/org/thoughtcrime/securesms/mediapreview/MediaIntentFactory.kt
index 2b53532b1..5593a45ab 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/mediapreview/MediaIntentFactory.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/mediapreview/MediaIntentFactory.kt
@@ -6,6 +6,9 @@ import android.net.Uri
import android.os.Bundle
import android.os.Parcelable
import kotlinx.parcelize.Parcelize
+import org.thoughtcrime.securesms.attachments.DatabaseAttachment
+import org.thoughtcrime.securesms.database.MediaDatabase
+import org.thoughtcrime.securesms.database.MediaDatabase.MediaRecord
object MediaIntentFactory {
private const val ARGS_KEY = "args"
@@ -34,7 +37,7 @@ object MediaIntentFactory {
val hideAllMedia: Boolean = false,
val showThread: Boolean = false,
val allMediaInRail: Boolean = false,
- val sorting: Int,
+ val sorting: MediaDatabase.Sorting,
val isVideoGif: Boolean
) : Parcelable
@@ -45,4 +48,26 @@ object MediaIntentFactory {
fun create(context: Context, args: MediaPreviewArgs): Intent {
return Intent(context, MediaPreviewV2Activity::class.java).putExtra(ARGS_KEY, args)
}
+
+ fun intentFromMediaRecord(
+ context: Context,
+ mediaRecord: MediaRecord,
+ leftIsRecent: Boolean
+ ): Intent {
+ val attachment: DatabaseAttachment = mediaRecord.attachment!!
+ return create(
+ context,
+ MediaPreviewArgs(
+ mediaRecord.threadId,
+ mediaRecord.date,
+ attachment.uri!!,
+ attachment.contentType,
+ attachment.size,
+ attachment.caption,
+ leftIsRecent,
+ sorting = MediaDatabase.Sorting.Newest,
+ isVideoGif = attachment.isVideoGif
+ )
+ )
+ }
}
diff --git a/app/src/main/java/org/thoughtcrime/securesms/mediapreview/MediaPreviewV2Fragment.kt b/app/src/main/java/org/thoughtcrime/securesms/mediapreview/MediaPreviewV2Fragment.kt
index 04fb32561..a91ccc2e1 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/mediapreview/MediaPreviewV2Fragment.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/mediapreview/MediaPreviewV2Fragment.kt
@@ -92,7 +92,7 @@ class MediaPreviewV2Fragment : Fragment(R.layout.fragment_media_preview_v2), Med
}.show()
}
viewModel.initialize(args.showThread, args.allMediaInRail, args.leftIsRecent)
- val sorting = MediaDatabase.Sorting.deserialize(args.sorting)
+ val sorting = MediaDatabase.Sorting.deserialize(args.sorting.ordinal)
viewModel.fetchAttachments(PartAuthority.requireAttachmentId(args.initialMediaUri), args.threadId, sorting)
}
@@ -442,5 +442,10 @@ class MediaPreviewV2Fragment : Fragment(R.layout.fragment_media_preview_v2), Med
companion object {
const val ARGS_KEY: String = "args"
+
+ @JvmStatic
+ fun isContentTypeSupported(contentType: String?): Boolean {
+ return MediaUtil.isImageType(contentType) || MediaUtil.isVideoType(contentType)
+ }
}
}
diff --git a/app/src/main/java/org/thoughtcrime/securesms/mms/AttachmentManager.java b/app/src/main/java/org/thoughtcrime/securesms/mms/AttachmentManager.java
index e54cb2179..d6a8239ee 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/mms/AttachmentManager.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/mms/AttachmentManager.java
@@ -41,7 +41,6 @@ import androidx.fragment.app.Fragment;
import org.signal.core.util.ThreadUtil;
import org.signal.core.util.logging.Log;
-import org.thoughtcrime.securesms.MediaPreviewActivity;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.attachments.Attachment;
import org.thoughtcrime.securesms.components.AudioView;
@@ -56,6 +55,7 @@ import org.thoughtcrime.securesms.database.MediaDatabase;
import org.thoughtcrime.securesms.giph.ui.GiphyActivity;
import org.thoughtcrime.securesms.maps.PlacePickerActivity;
import org.thoughtcrime.securesms.mediapreview.MediaIntentFactory;
+import org.thoughtcrime.securesms.mediapreview.MediaPreviewV2Fragment;
import org.thoughtcrime.securesms.mediasend.v2.MediaSelectionActivity;
import org.thoughtcrime.securesms.payments.create.CreatePaymentFragmentArgs;
import org.thoughtcrime.securesms.payments.preferences.PaymentsActivity;
@@ -470,7 +470,7 @@ public class AttachmentManager {
}
private void previewImageDraft(final @NonNull Slide slide) {
- if (MediaPreviewActivity.isContentTypeSupported(slide.getContentType()) && slide.getUri() != null) {
+ if (MediaPreviewV2Fragment.isContentTypeSupported(slide.getContentType()) && slide.getUri() != null) {
MediaIntentFactory.MediaPreviewArgs args = new MediaIntentFactory.MediaPreviewArgs(
MediaIntentFactory.NOT_IN_A_THREAD,
MediaIntentFactory.UNKNOWN_TIMESTAMP,
@@ -482,7 +482,7 @@ public class AttachmentManager {
false,
false,
false,
- MediaDatabase.Sorting.Newest.ordinal(),
+ MediaDatabase.Sorting.Newest,
slide.isVideoGif());
context.startActivity(MediaIntentFactory.create(context, args));
}