diff --git a/app/src/main/java/org/thoughtcrime/securesms/MediaPreviewActivity.java b/app/src/main/java/org/thoughtcrime/securesms/MediaPreviewActivity.java
index 0dfb5a705..a1d6a2289 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/MediaPreviewActivity.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/MediaPreviewActivity.java
@@ -24,7 +24,6 @@ import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.os.AsyncTask;
-import android.os.Build;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuInflater;
@@ -490,17 +489,8 @@ public final class MediaPreviewActivity extends PassphraseRequiredActivity
@Override
public boolean onPrepareOptionsMenu(Menu menu) {
if (!isMediaInDb()) {
- menu.findItem(R.id.media_preview__overview).setVisible(false);
menu.findItem(R.id.delete).setVisible(false);
}
-
- // Restricted to API26 because of MemoryFileUtil not supporting lower API levels well
- menu.findItem(R.id.media_preview__share).setVisible(Build.VERSION.SDK_INT >= 26);
-
- if (cameFromAllMedia) {
- menu.findItem(R.id.media_preview__overview).setVisible(false);
- }
-
super.onPrepareOptionsMenu(menu);
return true;
}
@@ -511,9 +501,6 @@ public final class MediaPreviewActivity extends PassphraseRequiredActivity
int itemId = item.getItemId();
- if (itemId == R.id.media_preview__overview) { showOverview(); return true; }
- if (itemId == R.id.media_preview__forward) { forward(); return true; }
- if (itemId == R.id.media_preview__share) { share(); return true; }
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; }
@@ -701,7 +688,7 @@ public final class MediaPreviewActivity extends PassphraseRequiredActivity
@Override
public @Nullable View getPlaybackControls(int position) {
if (mediaPreviewFragment != null) {
- return mediaPreviewFragment.getPlaybackControls();
+ return mediaPreviewFragment.getBottomBarControls();
}
return null;
}
@@ -831,7 +818,7 @@ public final class MediaPreviewActivity extends PassphraseRequiredActivity
@Override
public @Nullable View getPlaybackControls(int position) {
MediaPreviewFragment mediaView = mediaFragments.get(position);
- if (mediaView != null) return mediaView.getPlaybackControls();
+ if (mediaView != null) return mediaView.getBottomBarControls();
return null;
}
diff --git a/app/src/main/java/org/thoughtcrime/securesms/mediapreview/ImageMediaPreviewFragment.java b/app/src/main/java/org/thoughtcrime/securesms/mediapreview/ImageMediaPreviewFragment.java
index 73467069e..2e93f72ca 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/mediapreview/ImageMediaPreviewFragment.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/mediapreview/ImageMediaPreviewFragment.java
@@ -5,6 +5,7 @@ import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
+import android.widget.ImageButton;
import androidx.annotation.Nullable;
@@ -15,6 +16,7 @@ import org.thoughtcrime.securesms.mms.GlideRequests;
import org.thoughtcrime.securesms.util.MediaUtil;
public final class ImageMediaPreviewFragment extends MediaPreviewFragment {
+ private View bottomBarControlView;
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
@@ -39,6 +41,26 @@ public final class ImageMediaPreviewFragment extends MediaPreviewFragment {
zoomingImageView.setOnClickListener(v -> events.singleTapOnMedia());
+ bottomBarControlView = getLayoutInflater().inflate(R.layout.image_media_preview_bottom_bar, null);
return zoomingImageView;
}
+
+ @Override
+ public void setShareButtonListener(View.OnClickListener listener) {
+ ImageButton forwardButton = bottomBarControlView.findViewById(R.id.image_preview_forward);
+ forwardButton.setOnClickListener(listener);
+
+ }
+
+ @Override
+ public void setForwardButtonListener(View.OnClickListener listener) {
+ ImageButton shareButton = bottomBarControlView.findViewById(R.id.image_preview_share);
+ shareButton.setOnClickListener(listener);
+ }
+
+ @Nullable
+ @Override
+ public View getBottomBarControls() {
+ return bottomBarControlView;
+ }
}
diff --git a/app/src/main/java/org/thoughtcrime/securesms/mediapreview/MediaPreviewFragment.java b/app/src/main/java/org/thoughtcrime/securesms/mediapreview/MediaPreviewFragment.java
index b90686c46..81d99a8c9 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/mediapreview/MediaPreviewFragment.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/mediapreview/MediaPreviewFragment.java
@@ -87,9 +87,9 @@ public abstract class MediaPreviewFragment extends Fragment {
public void pause() {
}
- public @Nullable PlayerControlView getPlaybackControls() {
- return null;
- }
+ abstract public void setShareButtonListener(View.OnClickListener listener);
+ abstract public void setForwardButtonListener(View.OnClickListener listener);
+ abstract public @Nullable View getBottomBarControls();
private void checkMediaStillAvailable() {
if (attachmentId == null) {
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 3b818a8a7..53a901890 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/mediapreview/MediaPreviewV2Fragment.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/mediapreview/MediaPreviewV2Fragment.kt
@@ -7,6 +7,7 @@ import android.content.DialogInterface
import android.content.Intent
import android.os.Build
import android.os.Bundle
+import android.view.LayoutInflater
import android.view.Menu
import android.view.View
import android.view.ViewGroup
@@ -20,7 +21,6 @@ import androidx.fragment.app.viewModels
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.viewpager2.widget.ViewPager2.OFFSCREEN_PAGE_LIMIT_DEFAULT
import androidx.viewpager2.widget.ViewPager2.OnPageChangeCallback
-import com.google.android.exoplayer2.ui.PlayerControlView
import com.google.android.material.appbar.MaterialToolbar
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.android.material.snackbar.Snackbar
@@ -35,7 +35,6 @@ import org.thoughtcrime.securesms.conversation.mutiselect.forward.MultiselectFor
import org.thoughtcrime.securesms.conversation.mutiselect.forward.MultiselectForwardFragmentArgs
import org.thoughtcrime.securesms.database.MediaDatabase
import org.thoughtcrime.securesms.databinding.FragmentMediaPreviewV2Binding
-import org.thoughtcrime.securesms.mediaoverview.MediaOverviewActivity
import org.thoughtcrime.securesms.mediasend.Media
import org.thoughtcrime.securesms.mms.GlideApp
import org.thoughtcrime.securesms.mms.PartAuthority
@@ -64,13 +63,18 @@ class MediaPreviewV2Fragment : Fragment(R.layout.fragment_media_preview_v2), Med
fullscreenHelper = FullscreenHelper(requireActivity())
}
+ override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
+ lifecycleDisposable.bindTo(viewLifecycleOwner)
+ return super.onCreateView(inflater, container, savedInstanceState)
+ }
+
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val args = MediaIntentFactory.requireArguments(requireArguments())
initializeViewModel(args)
- initializeToolbar(binding.toolbar, args)
+ initializeToolbar(binding.toolbar)
initializeViewPager()
initializeFullScreenUi()
initializeAlbumRail()
@@ -96,19 +100,12 @@ class MediaPreviewV2Fragment : Fragment(R.layout.fragment_media_preview_v2), Med
viewModel.fetchAttachments(PartAuthority.requireAttachmentId(args.initialMediaUri), args.threadId, sorting)
}
- private fun initializeToolbar(toolbar: MaterialToolbar, args: MediaIntentFactory.MediaPreviewArgs) {
+ private fun initializeToolbar(toolbar: MaterialToolbar) {
toolbar.setNavigationOnClickListener {
requireActivity().onBackPressed()
}
binding.toolbar.inflateMenu(R.menu.media_preview)
-
- // Restricted to API26 because of MemoryFileUtil not supporting lower API levels well
- binding.toolbar.menu.findItem(R.id.media_preview__share).isVisible = Build.VERSION.SDK_INT >= 26
-
- if (args.hideAllMedia) {
- binding.toolbar.menu.findItem(R.id.media_preview__overview).isVisible = false
- }
}
private fun initializeViewPager() {
@@ -175,15 +172,11 @@ class MediaPreviewV2Fragment : Fragment(R.layout.fragment_media_preview_v2), Med
val menu: Menu = binding.toolbar.menu
if (currentItem.threadId == MediaIntentFactory.NOT_IN_A_THREAD.toLong()) {
- menu.findItem(R.id.media_preview__overview).isVisible = false
menu.findItem(R.id.delete).isVisible = false
}
binding.toolbar.setOnMenuItemClickListener {
when (it.itemId) {
- R.id.media_preview__overview -> showOverview(currentItem.threadId)
- R.id.media_preview__forward -> forward(currentItem)
- R.id.media_preview__share -> share(currentItem)
R.id.save -> saveToDisk(currentItem)
R.id.delete -> deleteMedia(currentItem)
android.R.id.home -> requireActivity().finish()
@@ -214,12 +207,16 @@ class MediaPreviewV2Fragment : Fragment(R.layout.fragment_media_preview_v2), Med
(binding.mediaPreviewAlbumRail.adapter as MediaRailAdapter).setMedia(albumThumbnailMedia, currentState.position)
binding.mediaPreviewAlbumRail.smoothScrollToPosition(currentState.position)
- binding.mediaPreviewCaptionContainer.visibility = if (caption == null) View.GONE else View.VISIBLE
- binding.mediaPreviewCaption.text = caption
+ if (caption != null) {
+ binding.mediaPreviewCaption.text = caption
+ binding.mediaPreviewCaption.visibility = View.VISIBLE
+ } else {
+ binding.mediaPreviewCaption.visibility = View.GONE
+ }
val fragmentTag = "f${currentState.position}"
- val currentFragment: Fragment? = childFragmentManager.findFragmentByTag(fragmentTag)
- val playbackControls: PlayerControlView? = (currentFragment as? MediaPreviewFragment)?.playbackControls
+ val currentFragment: MediaPreviewFragment? = childFragmentManager.findFragmentByTag(fragmentTag) as? MediaPreviewFragment
+ val playbackControls: View? = currentFragment?.bottomBarControls
if (albumThumbnailMedia.size <= 1 && caption == null && playbackControls == null) {
binding.mediaPreviewDetailsContainer.visibility = View.GONE
} else {
@@ -231,6 +228,8 @@ class MediaPreviewV2Fragment : Fragment(R.layout.fragment_media_preview_v2), Med
playbackControls.layoutParams = params
binding.mediaPreviewPlaybackControlsContainer.addView(playbackControls)
}
+ currentFragment?.setShareButtonListener { share(currentItem) }
+ currentFragment?.setForwardButtonListener { forward(currentItem) }
}
private fun getTitleText(mediaRecord: MediaDatabase.MediaRecord, showThread: Boolean): String {
@@ -319,11 +318,6 @@ class MediaPreviewV2Fragment : Fragment(R.layout.fragment_media_preview_v2), Med
Log.d(TAG, "onMediaReady()")
}
- private fun showOverview(threadId: Long) {
- val context = requireContext()
- context.startActivity(MediaOverviewActivity.forThread(context, threadId))
- }
-
private fun forward(mediaItem: MediaDatabase.MediaRecord) {
val attachment = mediaItem.attachment
val uri = attachment?.uri
diff --git a/app/src/main/java/org/thoughtcrime/securesms/mediapreview/VideoMediaPreviewFragment.java b/app/src/main/java/org/thoughtcrime/securesms/mediapreview/VideoMediaPreviewFragment.java
index 4adef0639..8530cd686 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/mediapreview/VideoMediaPreviewFragment.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/mediapreview/VideoMediaPreviewFragment.java
@@ -6,6 +6,7 @@ import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
+import android.widget.ImageButton;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -29,6 +30,8 @@ public final class VideoMediaPreviewFragment extends MediaPreviewFragment {
private VideoPlayer videoView;
private boolean isVideoGif;
+ private ImageButton shareButton;
+ private ImageButton forwardButton;
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
@@ -92,12 +95,16 @@ public final class VideoMediaPreviewFragment extends MediaPreviewFragment {
}
videoView.setOnClickListener(v -> events.singleTapOnMedia());
-
+ final PlayerControlView controlView = videoView.getControlView();
+ if (controlView != null) {
+ shareButton = controlView.findViewById(R.id.exo_share);
+ forwardButton = controlView.findViewById(R.id.exo_forward);
+ }
return itemView;
}
private void updateSkipButtonState() {
- final PlayerControlView playbackControls = getPlaybackControls();
+ final PlayerControlView playbackControls = getBottomBarControls();
if (playbackControls != null) {
boolean shouldShowSkipButtons = videoView.getDuration() > MINIMUM_DURATION_FOR_SKIP_MS;
playbackControls.setShowFastForwardButton(shouldShowSkipButtons);
@@ -142,9 +149,19 @@ public final class VideoMediaPreviewFragment extends MediaPreviewFragment {
}
}
+ @Override
+ public void setShareButtonListener(View.OnClickListener listener) {
+ shareButton.setOnClickListener(listener);
+ }
+
+ @Override
+ public void setForwardButtonListener(View.OnClickListener listener) {
+ forwardButton.setOnClickListener(listener);
+ }
+
@Nullable
@Override
- public PlayerControlView getPlaybackControls() {
+ public PlayerControlView getBottomBarControls() {
return videoView != null && !isVideoGif ? videoView.getControlView() : null;
}
diff --git a/app/src/main/java/org/thoughtcrime/securesms/util/FeatureFlags.java b/app/src/main/java/org/thoughtcrime/securesms/util/FeatureFlags.java
index 7b9e84b47..5000d513c 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/util/FeatureFlags.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/util/FeatureFlags.java
@@ -102,7 +102,6 @@ public final class FeatureFlags {
private static final String SMS_EXPORTER = "android.sms.exporter.2";
public static final String STORIES_LOCALE = "android.stories.locale.1";
private static final String HIDE_CONTACTS = "android.hide.contacts";
- private static final String MEDIA_PREVIEW_V2 = "android.mediaPreviewV2";
private static final String SMS_EXPORT_MEGAPHONE_DELAY_DAYS = "android.smsExport.megaphoneDelayDays";
public static final String CREDIT_CARD_PAYMENTS = "android.credit.card.payments";
@@ -159,7 +158,6 @@ public final class FeatureFlags {
SMS_EXPORTER,
STORIES_LOCALE,
HIDE_CONTACTS,
- MEDIA_PREVIEW_V2,
SMS_EXPORT_MEGAPHONE_DELAY_DAYS,
CREDIT_CARD_PAYMENTS
);
@@ -557,13 +555,6 @@ public final class FeatureFlags {
return getBoolean(HIDE_CONTACTS, false);
}
- /**
- * Whether or not we should use the new media preview fragment implementation.
- */
- public static boolean mediaPreviewV2() {
- return getBoolean(MEDIA_PREVIEW_V2, false);
- }
-
/**
* Number of days to postpone the sms export megaphone and Phase 1 start.
*/
diff --git a/app/src/main/java/org/thoughtcrime/securesms/video/VideoPlayer.java b/app/src/main/java/org/thoughtcrime/securesms/video/VideoPlayer.java
index 6367a9a3c..3a5a57f0b 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/video/VideoPlayer.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/video/VideoPlayer.java
@@ -90,8 +90,7 @@ public class VideoPlayer extends FrameLayout {
this.mediaSourceFactory = new DefaultMediaSourceFactory(context);
this.exoView = findViewById(R.id.video_view);
- this.exoControls = new PlayerControlView(getContext());
- this.exoControls.setShowTimeoutMs(-1);
+ this.exoControls = createPlayerControls(getContext());
this.exoPlayerListener = new ExoPlayerListener();
this.playerListener = new Player.Listener() {
@@ -129,6 +128,14 @@ public class VideoPlayer extends FrameLayout {
};
}
+ private PlayerControlView createPlayerControls(Context context) {
+ final PlayerControlView playerControlView = new PlayerControlView(context);
+ playerControlView.setShowTimeoutMs(-1);
+ playerControlView.setShowNextButton(false);
+ playerControlView.setShowPreviousButton(false);
+ return playerControlView;
+ }
+
private MediaItem mediaItem;
public void setVideoSource(@NonNull VideoSlide videoSource, boolean autoplay, String poolTag) {
diff --git a/app/src/main/res/drawable/ic_share_24_outline_white.xml b/app/src/main/res/drawable/ic_share_24_outline_white.xml
new file mode 100644
index 000000000..a9ea18e34
--- /dev/null
+++ b/app/src/main/res/drawable/ic_share_24_outline_white.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/layout/exo_player_control_view.xml b/app/src/main/res/layout/exo_player_control_view.xml
new file mode 100644
index 000000000..6e4721117
--- /dev/null
+++ b/app/src/main/res/layout/exo_player_control_view.xml
@@ -0,0 +1,119 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/fragment_media_preview_v2.xml b/app/src/main/res/layout/fragment_media_preview_v2.xml
index 83802f0b5..2fec133be 100644
--- a/app/src/main/res/layout/fragment_media_preview_v2.xml
+++ b/app/src/main/res/layout/fragment_media_preview_v2.xml
@@ -24,27 +24,17 @@
android:visibility="gone"
tools:visibility="visible">
-
-
-
-
-
+ android:paddingStart="16dp"
+ android:paddingEnd="16dp"
+ android:paddingBottom="8dp"
+ style="@style/Signal.Text.Body"
+ android:textColor="@color/core_white"
+ android:gravity="bottom"
+ tools:text="With great power comes great responsibility." />
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/menu/media_preview.xml b/app/src/main/res/menu/media_preview.xml
index b727524b0..b44746460 100644
--- a/app/src/main/res/menu/media_preview.xml
+++ b/app/src/main/res/menu/media_preview.xml
@@ -1,23 +1,12 @@
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index d2c4cffd9..9afcbb416 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -3237,6 +3237,8 @@
Forward
Share
All media
+ Edit
+
Media preview