kopia lustrzana https://github.com/ryukoposting/Signal-Android
Add seek buttons for videos longer than 30s.
rodzic
7f4e964ec8
commit
32fbbf2b55
|
@ -9,6 +9,8 @@ import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.fragment.app.Fragment;
|
import androidx.fragment.app.Fragment;
|
||||||
|
|
||||||
|
import com.google.android.exoplayer2.ui.PlayerControlView;
|
||||||
|
|
||||||
import org.thoughtcrime.securesms.attachments.Attachment;
|
import org.thoughtcrime.securesms.attachments.Attachment;
|
||||||
import org.thoughtcrime.securesms.attachments.AttachmentId;
|
import org.thoughtcrime.securesms.attachments.AttachmentId;
|
||||||
import org.thoughtcrime.securesms.database.SignalDatabase;
|
import org.thoughtcrime.securesms.database.SignalDatabase;
|
||||||
|
@ -85,7 +87,7 @@ public abstract class MediaPreviewFragment extends Fragment {
|
||||||
public void pause() {
|
public void pause() {
|
||||||
}
|
}
|
||||||
|
|
||||||
public @Nullable View getPlaybackControls() {
|
public @Nullable PlayerControlView getPlaybackControls() {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,7 @@ import androidx.fragment.app.viewModels
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import androidx.viewpager2.widget.ViewPager2.OFFSCREEN_PAGE_LIMIT_DEFAULT
|
import androidx.viewpager2.widget.ViewPager2.OFFSCREEN_PAGE_LIMIT_DEFAULT
|
||||||
import androidx.viewpager2.widget.ViewPager2.OnPageChangeCallback
|
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.appbar.MaterialToolbar
|
||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
import com.google.android.material.snackbar.Snackbar
|
import com.google.android.material.snackbar.Snackbar
|
||||||
|
@ -199,8 +200,7 @@ class MediaPreviewV2Fragment : Fragment(R.layout.fragment_media_preview_v2), Med
|
||||||
*/
|
*/
|
||||||
private fun bindLoadedState(currentState: MediaPreviewV2State) {
|
private fun bindLoadedState(currentState: MediaPreviewV2State) {
|
||||||
val currentItem: MediaDatabase.MediaRecord = currentState.mediaRecords[currentState.position]
|
val currentItem: MediaDatabase.MediaRecord = currentState.mediaRecords[currentState.position]
|
||||||
val currentFragment: Fragment? = childFragmentManager.findFragmentByTag("f${currentState.position}")
|
|
||||||
val playbackControls = (currentFragment as? MediaPreviewFragment)?.playbackControls
|
|
||||||
val albumThumbnailMedia = if (currentState.allMediaInAlbumRail) {
|
val albumThumbnailMedia = if (currentState.allMediaInAlbumRail) {
|
||||||
currentState.mediaRecords.map { it.toMedia() }
|
currentState.mediaRecords.map { it.toMedia() }
|
||||||
} else {
|
} else {
|
||||||
|
@ -209,11 +209,7 @@ class MediaPreviewV2Fragment : Fragment(R.layout.fragment_media_preview_v2), Med
|
||||||
.map { it.toMedia() }
|
.map { it.toMedia() }
|
||||||
}
|
}
|
||||||
val caption = currentItem.attachment?.caption
|
val caption = currentItem.attachment?.caption
|
||||||
if (albumThumbnailMedia.size <= 1 && caption == null && playbackControls == null) {
|
|
||||||
binding.mediaPreviewDetailsContainer.visibility = View.GONE
|
|
||||||
} else {
|
|
||||||
binding.mediaPreviewDetailsContainer.visibility = View.VISIBLE
|
|
||||||
}
|
|
||||||
binding.mediaPreviewAlbumRail.visibility = if (albumThumbnailMedia.size <= 1) View.GONE else View.VISIBLE
|
binding.mediaPreviewAlbumRail.visibility = if (albumThumbnailMedia.size <= 1) View.GONE else View.VISIBLE
|
||||||
(binding.mediaPreviewAlbumRail.adapter as MediaRailAdapter).setMedia(albumThumbnailMedia, currentState.position)
|
(binding.mediaPreviewAlbumRail.adapter as MediaRailAdapter).setMedia(albumThumbnailMedia, currentState.position)
|
||||||
binding.mediaPreviewAlbumRail.smoothScrollToPosition(currentState.position)
|
binding.mediaPreviewAlbumRail.smoothScrollToPosition(currentState.position)
|
||||||
|
@ -221,13 +217,19 @@ class MediaPreviewV2Fragment : Fragment(R.layout.fragment_media_preview_v2), Med
|
||||||
binding.mediaPreviewCaptionContainer.visibility = if (caption == null) View.GONE else View.VISIBLE
|
binding.mediaPreviewCaptionContainer.visibility = if (caption == null) View.GONE else View.VISIBLE
|
||||||
binding.mediaPreviewCaption.text = caption
|
binding.mediaPreviewCaption.text = caption
|
||||||
|
|
||||||
|
val fragmentTag = "f${currentState.position}"
|
||||||
|
val currentFragment: Fragment? = childFragmentManager.findFragmentByTag(fragmentTag)
|
||||||
|
val playbackControls: PlayerControlView? = (currentFragment as? MediaPreviewFragment)?.playbackControls
|
||||||
|
if (albumThumbnailMedia.size <= 1 && caption == null && playbackControls == null) {
|
||||||
|
binding.mediaPreviewDetailsContainer.visibility = View.GONE
|
||||||
|
} else {
|
||||||
|
binding.mediaPreviewDetailsContainer.visibility = View.VISIBLE
|
||||||
|
}
|
||||||
|
binding.mediaPreviewPlaybackControlsContainer.removeAllViews()
|
||||||
if (playbackControls != null) {
|
if (playbackControls != null) {
|
||||||
val params = ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
|
val params = ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
|
||||||
playbackControls.layoutParams = params
|
playbackControls.layoutParams = params
|
||||||
binding.mediaPreviewPlaybackControlsContainer.removeAllViews()
|
|
||||||
binding.mediaPreviewPlaybackControlsContainer.addView(playbackControls)
|
binding.mediaPreviewPlaybackControlsContainer.addView(playbackControls)
|
||||||
} else {
|
|
||||||
binding.mediaPreviewPlaybackControlsContainer.removeAllViews()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,8 @@ import android.view.ViewGroup;
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
|
import com.google.android.exoplayer2.ui.PlayerControlView;
|
||||||
|
|
||||||
import org.signal.core.util.logging.Log;
|
import org.signal.core.util.logging.Log;
|
||||||
import org.thoughtcrime.securesms.R;
|
import org.thoughtcrime.securesms.R;
|
||||||
import org.thoughtcrime.securesms.components.voice.VoiceNoteMediaControllerOwner;
|
import org.thoughtcrime.securesms.components.voice.VoiceNoteMediaControllerOwner;
|
||||||
|
@ -17,10 +19,14 @@ import org.thoughtcrime.securesms.mms.VideoSlide;
|
||||||
import org.thoughtcrime.securesms.util.MediaUtil;
|
import org.thoughtcrime.securesms.util.MediaUtil;
|
||||||
import org.thoughtcrime.securesms.video.VideoPlayer;
|
import org.thoughtcrime.securesms.video.VideoPlayer;
|
||||||
|
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
public final class VideoMediaPreviewFragment extends MediaPreviewFragment {
|
public final class VideoMediaPreviewFragment extends MediaPreviewFragment {
|
||||||
|
|
||||||
private static final String TAG = Log.tag(VideoMediaPreviewFragment.class);
|
private static final String TAG = Log.tag(VideoMediaPreviewFragment.class);
|
||||||
|
|
||||||
|
private static final Long MINIMUM_DURATION_FOR_SKIP_MS = TimeUnit.MILLISECONDS.convert(30, TimeUnit.SECONDS);
|
||||||
|
|
||||||
private VideoPlayer videoView;
|
private VideoPlayer videoView;
|
||||||
private boolean isVideoGif;
|
private boolean isVideoGif;
|
||||||
|
|
||||||
|
@ -90,6 +96,15 @@ public final class VideoMediaPreviewFragment extends MediaPreviewFragment {
|
||||||
return itemView;
|
return itemView;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void updateSkipButtonState() {
|
||||||
|
final PlayerControlView playbackControls = getPlaybackControls();
|
||||||
|
if (playbackControls != null) {
|
||||||
|
boolean shouldShowSkipButtons = videoView.getDuration() > MINIMUM_DURATION_FOR_SKIP_MS;
|
||||||
|
playbackControls.setShowFastForwardButton(shouldShowSkipButtons);
|
||||||
|
playbackControls.setShowRewindButton(shouldShowSkipButtons);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDestroyView() {
|
public void onDestroyView() {
|
||||||
super.onDestroyView();
|
super.onDestroyView();
|
||||||
|
@ -127,8 +142,9 @@ public final class VideoMediaPreviewFragment extends MediaPreviewFragment {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public View getPlaybackControls() {
|
public PlayerControlView getPlaybackControls() {
|
||||||
return videoView != null && !isVideoGif ? videoView.getControlView() : null;
|
return videoView != null && !isVideoGif ? videoView.getControlView() : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -222,7 +222,7 @@ public class VideoPlayer extends FrameLayout {
|
||||||
super.setOnClickListener(l);
|
super.setOnClickListener(l);
|
||||||
}
|
}
|
||||||
|
|
||||||
public @Nullable View getControlView() {
|
public @Nullable PlayerControlView getControlView() {
|
||||||
return this.exoControls;
|
return this.exoControls;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -61,6 +61,8 @@ class SimpleExoPlayerPool(context: Context) : ExoPlayerPool<ExoPlayer>(MAXIMUM_R
|
||||||
override fun createPlayer(): ExoPlayer {
|
override fun createPlayer(): ExoPlayer {
|
||||||
return ExoPlayer.Builder(context)
|
return ExoPlayer.Builder(context)
|
||||||
.setMediaSourceFactory(mediaSourceFactory)
|
.setMediaSourceFactory(mediaSourceFactory)
|
||||||
|
.setSeekBackIncrementMs(SEEK_INTERVAL.inWholeMilliseconds)
|
||||||
|
.setSeekForwardIncrementMs(SEEK_INTERVAL.inWholeMilliseconds)
|
||||||
.build()
|
.build()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -68,6 +70,7 @@ class SimpleExoPlayerPool(context: Context) : ExoPlayerPool<ExoPlayer>(MAXIMUM_R
|
||||||
private const val MAXIMUM_RESERVED_PLAYERS = 1
|
private const val MAXIMUM_RESERVED_PLAYERS = 1
|
||||||
private const val MAXIMUM_SUPPORTED_PLAYBACK_PRE_23 = 6
|
private const val MAXIMUM_SUPPORTED_PLAYBACK_PRE_23 = 6
|
||||||
private const val MAXIMUM_SUPPORTED_PLAYBACK_PRE_23_LOW_MEM = 3
|
private const val MAXIMUM_SUPPORTED_PLAYBACK_PRE_23_LOW_MEM = 3
|
||||||
|
private val SEEK_INTERVAL = 15.seconds
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Ładowanie…
Reference in New Issue