kopia lustrzana https://github.com/ryukoposting/Signal-Android
Media Preview V2 Visual Redesign.
rodzic
b8174c5e00
commit
7759ad283d
|
@ -5,7 +5,6 @@ import android.os.Bundle;
|
|||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ImageButton;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
|
@ -16,7 +15,7 @@ import org.thoughtcrime.securesms.mms.GlideRequests;
|
|||
import org.thoughtcrime.securesms.util.MediaUtil;
|
||||
|
||||
public final class ImageMediaPreviewFragment extends MediaPreviewFragment {
|
||||
private View bottomBarControlView;
|
||||
private MediaPreviewPlayerControlView bottomBarControlView;
|
||||
|
||||
@Override
|
||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
|
@ -41,26 +40,24 @@ 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);
|
||||
|
||||
public void cleanUp() {
|
||||
bottomBarControlView = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setForwardButtonListener(View.OnClickListener listener) {
|
||||
ImageButton shareButton = bottomBarControlView.findViewById(R.id.image_preview_share);
|
||||
shareButton.setOnClickListener(listener);
|
||||
}
|
||||
public void pause() {}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public View getBottomBarControls() {
|
||||
public ViewGroup getBottomBarControls() {
|
||||
return bottomBarControlView;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBottomButtonControls(MediaPreviewPlayerControlView playerControlView) {
|
||||
bottomBarControlView = playerControlView;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,14 +3,12 @@ package org.thoughtcrime.securesms.mediapreview;
|
|||
import android.content.Context;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
||||
import com.google.android.exoplayer2.ui.PlayerControlView;
|
||||
|
||||
import org.thoughtcrime.securesms.attachments.Attachment;
|
||||
import org.thoughtcrime.securesms.attachments.AttachmentId;
|
||||
import org.thoughtcrime.securesms.database.SignalDatabase;
|
||||
|
@ -81,15 +79,10 @@ public abstract class MediaPreviewFragment extends Fragment {
|
|||
checkMediaStillAvailable();
|
||||
}
|
||||
|
||||
public void cleanUp() {
|
||||
}
|
||||
|
||||
public void pause() {
|
||||
}
|
||||
|
||||
abstract public void setShareButtonListener(View.OnClickListener listener);
|
||||
abstract public void setForwardButtonListener(View.OnClickListener listener);
|
||||
abstract public @Nullable View getBottomBarControls();
|
||||
public abstract void cleanUp();
|
||||
public abstract void pause();
|
||||
public abstract ViewGroup getBottomBarControls();
|
||||
public abstract void setBottomButtonControls(MediaPreviewPlayerControlView playerControlView);
|
||||
|
||||
private void checkMediaStillAvailable() {
|
||||
if (attachmentId == null) {
|
||||
|
|
|
@ -0,0 +1,58 @@
|
|||
package org.thoughtcrime.securesms.mediapreview
|
||||
|
||||
import android.content.Context
|
||||
import android.util.AttributeSet
|
||||
import android.widget.ImageButton
|
||||
import android.widget.LinearLayout
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.google.android.exoplayer2.ui.PlayerControlView
|
||||
import org.thoughtcrime.securesms.R
|
||||
import org.thoughtcrime.securesms.util.MediaUtil
|
||||
|
||||
/**
|
||||
* The bottom bar for the media preview. This includes the standard seek bar as well as playback controls,
|
||||
* but adds forward and share buttons as well as a recyclerview that can be populated with a rail of thumbnails.
|
||||
*/
|
||||
class MediaPreviewPlayerControlView @JvmOverloads constructor(
|
||||
context: Context,
|
||||
attrs: AttributeSet? = null,
|
||||
defStyleAttr: Int = 0,
|
||||
playbackAttrs: AttributeSet? = null
|
||||
) : PlayerControlView(context, attrs, defStyleAttr, playbackAttrs) {
|
||||
|
||||
val recyclerView: RecyclerView = findViewById(R.id.media_preview_album_rail)
|
||||
private val durationBar: LinearLayout = findViewById(R.id.exo_duration_viewgroup)
|
||||
private val videoControls: LinearLayout = findViewById(R.id.exo_button_viewgroup)
|
||||
private val shareButton: ImageButton = findViewById(R.id.exo_share)
|
||||
private val forwardButton: ImageButton = findViewById(R.id.exo_forward)
|
||||
|
||||
enum class MediaMode {
|
||||
IMAGE, VIDEO;
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun fromString(contentType: String): MediaMode {
|
||||
if (MediaUtil.isVideo(contentType)) return VIDEO
|
||||
if (MediaUtil.isImageType(contentType)) return IMAGE
|
||||
throw IllegalArgumentException("Unknown content type: $contentType")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
init {
|
||||
setShowPreviousButton(false)
|
||||
setShowNextButton(false)
|
||||
showShuffleButton = false
|
||||
showVrButton = false
|
||||
showTimeoutMs = -1
|
||||
}
|
||||
|
||||
fun setVisibility(mediaMode: MediaMode) {
|
||||
durationBar.visibility = if (mediaMode == MediaMode.VIDEO) VISIBLE else GONE
|
||||
videoControls.visibility = if (mediaMode == MediaMode.VIDEO) VISIBLE else INVISIBLE
|
||||
}
|
||||
|
||||
fun setShareButtonListener(listener: OnClickListener?) = shareButton.setOnClickListener(listener)
|
||||
|
||||
fun setForwardButtonListener(listener: OnClickListener?) = forwardButton.setOnClickListener(listener)
|
||||
}
|
|
@ -20,7 +20,7 @@ class MediaPreviewV2Activity : AppCompatActivity(R.layout.activity_mediapreview_
|
|||
super.onCreate(savedInstanceState)
|
||||
setTheme(R.style.TextSecure_MediaPreview)
|
||||
if (Build.VERSION.SDK_INT >= 21) {
|
||||
val systemBarColor = ContextCompat.getColor(this, R.color.media_preview_bar_background)
|
||||
val systemBarColor = ContextCompat.getColor(this, R.color.signal_dark_colorSurface)
|
||||
window.statusBarColor = systemBarColor
|
||||
window.navigationBarColor = systemBarColor
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@ import androidx.core.view.ViewCompat
|
|||
import androidx.core.view.WindowInsetsCompat
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.viewModels
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.viewpager2.widget.ViewPager2.OFFSCREEN_PAGE_LIMIT_DEFAULT
|
||||
import androidx.viewpager2.widget.ViewPager2.OnPageChangeCallback
|
||||
import com.google.android.material.appbar.MaterialToolbar
|
||||
|
@ -72,12 +72,10 @@ class MediaPreviewV2Fragment : Fragment(R.layout.fragment_media_preview_v2), Med
|
|||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
val args = MediaIntentFactory.requireArguments(requireArguments())
|
||||
|
||||
initializeViewModel(args)
|
||||
initializeToolbar(binding.toolbar)
|
||||
initializeViewPager()
|
||||
initializeFullScreenUi()
|
||||
initializeAlbumRail()
|
||||
anchorMarginsToBottomInsets(binding.mediaPreviewDetailsContainer)
|
||||
lifecycleDisposable += viewModel.state.distinctUntilChanged().observeOn(AndroidSchedulers.mainThread()).subscribe {
|
||||
bindCurrentState(it)
|
||||
|
@ -92,10 +90,7 @@ class MediaPreviewV2Fragment : Fragment(R.layout.fragment_media_preview_v2), Med
|
|||
requireActivity().finish()
|
||||
}.show()
|
||||
}
|
||||
|
||||
viewModel.setShowThread(args.showThread)
|
||||
viewModel.setAlwaysShowAlbumRail(args.allMediaInRail)
|
||||
viewModel.setLeftIsRecent(args.leftIsRecent)
|
||||
viewModel.initialize(args.showThread, args.allMediaInRail, args.leftIsRecent)
|
||||
val sorting = MediaDatabase.Sorting.deserialize(args.sorting)
|
||||
viewModel.fetchAttachments(PartAuthority.requireAttachmentId(args.initialMediaUri), args.threadId, sorting)
|
||||
}
|
||||
|
@ -105,6 +100,8 @@ class MediaPreviewV2Fragment : Fragment(R.layout.fragment_media_preview_v2), Med
|
|||
requireActivity().onBackPressed()
|
||||
}
|
||||
|
||||
toolbar.setTitleTextAppearance(requireContext(), R.style.Signal_Text_TitleMedium)
|
||||
toolbar.setSubtitleTextAppearance(requireContext(), R.style.Signal_Text_BodyMedium)
|
||||
binding.toolbar.inflateMenu(R.menu.media_preview)
|
||||
}
|
||||
|
||||
|
@ -123,10 +120,9 @@ class MediaPreviewV2Fragment : Fragment(R.layout.fragment_media_preview_v2), Med
|
|||
})
|
||||
}
|
||||
|
||||
private fun initializeAlbumRail() {
|
||||
binding.mediaPreviewAlbumRail.itemAnimator = null // Or can crash when set to INVISIBLE while animating by FullscreenHelper https://issuetracker.google.com/issues/148720682
|
||||
binding.mediaPreviewAlbumRail.layoutManager = LinearLayoutManager(requireContext(), LinearLayoutManager.HORIZONTAL, false)
|
||||
binding.mediaPreviewAlbumRail.adapter = MediaRailAdapter(
|
||||
private fun initializeAlbumRail(recyclerView: RecyclerView, albumThumbnailMedia: List<Media?>, albumPosition: Int) {
|
||||
recyclerView.itemAnimator = null // Or can crash when set to INVISIBLE while animating by FullscreenHelper https://issuetracker.google.com/issues/148720682
|
||||
val mediaRailAdapter = MediaRailAdapter(
|
||||
GlideApp.with(this),
|
||||
object : MediaRailAdapter.RailItemListener {
|
||||
override fun onRailItemClicked(distanceFromActive: Int) {
|
||||
|
@ -139,6 +135,9 @@ class MediaPreviewV2Fragment : Fragment(R.layout.fragment_media_preview_v2), Med
|
|||
},
|
||||
false
|
||||
)
|
||||
mediaRailAdapter.setMedia(albumThumbnailMedia, albumPosition)
|
||||
recyclerView.adapter = mediaRailAdapter
|
||||
recyclerView.smoothScrollToPosition(albumPosition)
|
||||
}
|
||||
|
||||
private fun initializeFullScreenUi() {
|
||||
|
@ -152,21 +151,43 @@ class MediaPreviewV2Fragment : Fragment(R.layout.fragment_media_preview_v2), Med
|
|||
return
|
||||
}
|
||||
when (currentState.loadState) {
|
||||
MediaPreviewV2State.LoadState.READY -> bindReadyState(currentState)
|
||||
MediaPreviewV2State.LoadState.LOADED -> {
|
||||
bindReadyState(currentState)
|
||||
bindLoadedState(currentState)
|
||||
}
|
||||
MediaPreviewV2State.LoadState.DATA_LOADED -> bindDataLoadedState(currentState)
|
||||
MediaPreviewV2State.LoadState.MEDIA_READY -> bindMediaReadyState(currentState)
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
private fun bindReadyState(currentState: MediaPreviewV2State) {
|
||||
private fun bindDataLoadedState(currentState: MediaPreviewV2State) {
|
||||
(binding.mediaPager.adapter as MediaPreviewV2Adapter).updateBackingItems(currentState.mediaRecords.mapNotNull { it.attachment })
|
||||
if (binding.mediaPager.currentItem != currentState.position) {
|
||||
binding.mediaPager.setCurrentItem(currentState.position, false)
|
||||
val currentPosition = currentState.position
|
||||
if (binding.mediaPager.currentItem != currentPosition) {
|
||||
binding.mediaPager.setCurrentItem(currentPosition, false)
|
||||
}
|
||||
val currentItem: MediaDatabase.MediaRecord = currentState.mediaRecords[currentState.position]
|
||||
}
|
||||
|
||||
/**
|
||||
* These are binding steps that need a reference to the actual fragment within the pager.
|
||||
* This is not available until after a page has been chosen by the ViewPager, and we receive the
|
||||
* {@link OnPageChangeCallback}.
|
||||
*/
|
||||
private fun bindMediaReadyState(currentState: MediaPreviewV2State) {
|
||||
val currentPosition = currentState.position
|
||||
val currentItem: MediaDatabase.MediaRecord = currentState.mediaRecords[currentPosition]
|
||||
|
||||
// pause all other fragments
|
||||
childFragmentManager.fragments.map { fragment ->
|
||||
if (fragment.tag != "f$currentPosition") {
|
||||
(fragment as? MediaPreviewFragment)?.pause()
|
||||
}
|
||||
}
|
||||
|
||||
val mediaType: MediaPreviewPlayerControlView.MediaMode = if (currentItem.attachment?.isVideoGif == true) {
|
||||
MediaPreviewPlayerControlView.MediaMode.IMAGE
|
||||
} else {
|
||||
MediaPreviewPlayerControlView.MediaMode.fromString(currentItem.contentType)
|
||||
}
|
||||
binding.mediaPreviewPlaybackControls.setVisibility(mediaType)
|
||||
|
||||
binding.toolbar.title = getTitleText(currentItem, currentState.showThread)
|
||||
binding.toolbar.subtitle = getSubTitleText(currentItem)
|
||||
|
||||
|
@ -184,16 +205,6 @@ class MediaPreviewV2Fragment : Fragment(R.layout.fragment_media_preview_v2), Med
|
|||
}
|
||||
return@setOnMenuItemClickListener true
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* These are binding steps that need a reference to the actual fragment within the pager.
|
||||
* This is not available until after a page has been chosen by the ViewPager, and we receive the
|
||||
* {@link OnPageChangeCallback}.
|
||||
*/
|
||||
private fun bindLoadedState(currentState: MediaPreviewV2State) {
|
||||
val currentItem: MediaDatabase.MediaRecord = currentState.mediaRecords[currentState.position]
|
||||
|
||||
val albumThumbnailMedia = if (currentState.allMediaInAlbumRail) {
|
||||
currentState.mediaRecords.map { it.toMedia() }
|
||||
} else {
|
||||
|
@ -201,11 +212,10 @@ class MediaPreviewV2Fragment : Fragment(R.layout.fragment_media_preview_v2), Med
|
|||
.filter { it.attachment != null && it.attachment!!.mmsId == currentItem.attachment?.mmsId }
|
||||
.map { it.toMedia() }
|
||||
}
|
||||
|
||||
val caption = currentItem.attachment?.caption
|
||||
|
||||
binding.mediaPreviewAlbumRail.visibility = if (albumThumbnailMedia.size <= 1) View.GONE else View.VISIBLE
|
||||
(binding.mediaPreviewAlbumRail.adapter as MediaRailAdapter).setMedia(albumThumbnailMedia, currentState.position)
|
||||
binding.mediaPreviewAlbumRail.smoothScrollToPosition(currentState.position)
|
||||
val albumRailEnabled = albumThumbnailMedia.size > 1
|
||||
|
||||
if (caption != null) {
|
||||
binding.mediaPreviewCaption.text = caption
|
||||
|
@ -214,24 +224,21 @@ class MediaPreviewV2Fragment : Fragment(R.layout.fragment_media_preview_v2), Med
|
|||
binding.mediaPreviewCaption.visibility = View.GONE
|
||||
}
|
||||
|
||||
val fragmentTag = "f${currentState.position}"
|
||||
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 {
|
||||
binding.mediaPreviewDetailsContainer.visibility = View.VISIBLE
|
||||
binding.mediaPreviewPlaybackControls.setShareButtonListener { share(currentItem) }
|
||||
binding.mediaPreviewPlaybackControls.setForwardButtonListener { forward(currentItem) }
|
||||
|
||||
val albumRail: RecyclerView = binding.mediaPreviewPlaybackControls.findViewById(R.id.media_preview_album_rail)
|
||||
if (albumRailEnabled) {
|
||||
val albumPosition = albumThumbnailMedia.indexOfFirst { it?.uri == currentItem.attachment?.uri }
|
||||
initializeAlbumRail(albumRail, albumThumbnailMedia, albumPosition)
|
||||
}
|
||||
binding.mediaPreviewPlaybackControlsContainer.removeAllViews()
|
||||
if (playbackControls != null) {
|
||||
val params = ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
|
||||
playbackControls.layoutParams = params
|
||||
binding.mediaPreviewPlaybackControlsContainer.addView(playbackControls)
|
||||
}
|
||||
currentFragment?.setShareButtonListener { share(currentItem) }
|
||||
currentFragment?.setForwardButtonListener { forward(currentItem) }
|
||||
albumRail.visibility = if (albumRailEnabled) View.VISIBLE else View.GONE
|
||||
val currentFragment: MediaPreviewFragment? = getMediaPreviewFragmentFromChildFragmentManager(currentPosition)
|
||||
currentFragment?.setBottomButtonControls(binding.mediaPreviewPlaybackControls)
|
||||
}
|
||||
|
||||
private fun getMediaPreviewFragmentFromChildFragmentManager(currentPosition: Int) = childFragmentManager.findFragmentByTag("f$currentPosition") as? MediaPreviewFragment
|
||||
|
||||
private fun getTitleText(mediaRecord: MediaDatabase.MediaRecord, showThread: Boolean): String {
|
||||
val recipient: Recipient = Recipient.live(mediaRecord.recipientId).get()
|
||||
val defaultFromString: String = if (mediaRecord.isOutgoing) {
|
||||
|
@ -315,7 +322,7 @@ class MediaPreviewV2Fragment : Fragment(R.layout.fragment_media_preview_v2), Med
|
|||
}
|
||||
|
||||
override fun onMediaReady() {
|
||||
Log.d(TAG, "onMediaReady()")
|
||||
viewModel.setMediaReady()
|
||||
}
|
||||
|
||||
private fun forward(mediaItem: MediaDatabase.MediaRecord) {
|
||||
|
@ -400,6 +407,11 @@ class MediaPreviewV2Fragment : Fragment(R.layout.fragment_media_preview_v2), Med
|
|||
.show()
|
||||
}
|
||||
|
||||
override fun onPause() {
|
||||
super.onPause()
|
||||
getMediaPreviewFragmentFromChildFragmentManager(binding.mediaPager.currentItem)?.pause()
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val ARGS_KEY: String = "args"
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ data class MediaPreviewV2State(
|
|||
val position: Int = 0,
|
||||
val showThread: Boolean = false,
|
||||
val allMediaInAlbumRail: Boolean = false,
|
||||
val leftIsRecent: Boolean = false
|
||||
val leftIsRecent: Boolean = false,
|
||||
) {
|
||||
enum class LoadState { INIT, READY, LOADED }
|
||||
enum class LoadState { INIT, DATA_LOADED, MEDIA_READY }
|
||||
}
|
||||
|
|
|
@ -24,46 +24,44 @@ class MediaPreviewV2ViewModel : ViewModel() {
|
|||
|
||||
val state: Flowable<MediaPreviewV2State> = store.stateFlowable.observeOn(AndroidSchedulers.mainThread())
|
||||
|
||||
fun fetchAttachments(startingAttachmentId: AttachmentId, threadId: Long, sorting: MediaDatabase.Sorting) {
|
||||
disposables += store.update(repository.getAttachments(startingAttachmentId, threadId, sorting)) {
|
||||
result: MediaPreviewRepository.Result, oldState: MediaPreviewV2State ->
|
||||
if (oldState.leftIsRecent) {
|
||||
oldState.copy(
|
||||
position = result.initialPosition,
|
||||
mediaRecords = result.records,
|
||||
loadState = MediaPreviewV2State.LoadState.READY,
|
||||
)
|
||||
} else {
|
||||
oldState.copy(
|
||||
position = result.records.size - result.initialPosition - 1,
|
||||
mediaRecords = result.records.reversed(),
|
||||
loadState = MediaPreviewV2State.LoadState.READY,
|
||||
)
|
||||
fun fetchAttachments(startingAttachmentId: AttachmentId, threadId: Long, sorting: MediaDatabase.Sorting, forceRefresh: Boolean = false) {
|
||||
if (store.state.loadState == MediaPreviewV2State.LoadState.INIT || forceRefresh) {
|
||||
disposables += store.update(repository.getAttachments(startingAttachmentId, threadId, sorting)) {
|
||||
result: MediaPreviewRepository.Result, oldState: MediaPreviewV2State ->
|
||||
if (oldState.leftIsRecent) {
|
||||
oldState.copy(
|
||||
position = result.initialPosition,
|
||||
mediaRecords = result.records,
|
||||
loadState = MediaPreviewV2State.LoadState.DATA_LOADED,
|
||||
)
|
||||
} else {
|
||||
oldState.copy(
|
||||
position = result.records.size - result.initialPosition - 1,
|
||||
mediaRecords = result.records.reversed(),
|
||||
loadState = MediaPreviewV2State.LoadState.DATA_LOADED,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun setShowThread(value: Boolean) {
|
||||
store.update { oldState ->
|
||||
oldState.copy(showThread = value)
|
||||
}
|
||||
}
|
||||
|
||||
fun setAlwaysShowAlbumRail(value: Boolean) {
|
||||
store.update { oldState ->
|
||||
oldState.copy(allMediaInAlbumRail = value)
|
||||
}
|
||||
}
|
||||
|
||||
fun setLeftIsRecent(value: Boolean) {
|
||||
store.update { oldState ->
|
||||
oldState.copy(leftIsRecent = value)
|
||||
fun initialize(showThread: Boolean, allMediaInAlbumRail: Boolean, leftIsRecent: Boolean) {
|
||||
if (store.state.loadState == MediaPreviewV2State.LoadState.INIT) {
|
||||
store.update { oldState ->
|
||||
oldState.copy(showThread = showThread, allMediaInAlbumRail = allMediaInAlbumRail, leftIsRecent = leftIsRecent)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun setCurrentPage(position: Int) {
|
||||
store.update { oldState ->
|
||||
oldState.copy(position = position, loadState = MediaPreviewV2State.LoadState.LOADED)
|
||||
oldState.copy(position = position)
|
||||
}
|
||||
}
|
||||
|
||||
fun setMediaReady() {
|
||||
store.update { oldState ->
|
||||
oldState.copy(loadState = MediaPreviewV2State.LoadState.MEDIA_READY)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -6,7 +6,6 @@ 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;
|
||||
|
@ -30,8 +29,6 @@ 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) {
|
||||
|
@ -90,21 +87,15 @@ public final class VideoMediaPreviewFragment extends MediaPreviewFragment {
|
|||
});
|
||||
|
||||
if (isVideoGif) {
|
||||
videoView.hideControls();
|
||||
videoView.loopForever();
|
||||
}
|
||||
|
||||
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 = getBottomBarControls();
|
||||
final PlayerControlView playbackControls = videoView.getControlView();
|
||||
if (playbackControls != null) {
|
||||
boolean shouldShowSkipButtons = videoView.getDuration() > MINIMUM_DURATION_FOR_SKIP_MS;
|
||||
playbackControls.setShowFastForwardButton(shouldShowSkipButtons);
|
||||
|
@ -149,20 +140,16 @@ 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 getBottomBarControls() {
|
||||
return videoView != null && !isVideoGif ? videoView.getControlView() : null;
|
||||
public MediaPreviewPlayerControlView getBottomBarControls() {
|
||||
return (MediaPreviewPlayerControlView) videoView.getControlView();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBottomButtonControls(@NonNull MediaPreviewPlayerControlView playerControlView) {
|
||||
videoView.setControlView(playerControlView);
|
||||
updateSkipButtonState();
|
||||
}
|
||||
|
||||
private @NonNull Uri getUri() {
|
||||
|
|
|
@ -19,15 +19,12 @@ package org.thoughtcrime.securesms.video;
|
|||
import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
import android.view.Window;
|
||||
import android.view.WindowManager;
|
||||
import android.widget.FrameLayout;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.core.content.res.TypedArrayKt;
|
||||
import androidx.core.content.res.TypedArrayUtils;
|
||||
|
||||
import com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.ExoPlayer;
|
||||
|
@ -45,6 +42,7 @@ import com.google.android.exoplayer2.ui.PlayerView;
|
|||
import org.signal.core.util.logging.Log;
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
||||
import org.thoughtcrime.securesms.mediapreview.MediaPreviewPlayerControlView;
|
||||
import org.thoughtcrime.securesms.mms.VideoSlide;
|
||||
|
||||
import java.util.Objects;
|
||||
|
@ -56,10 +54,10 @@ public class VideoPlayer extends FrameLayout {
|
|||
private static final String TAG = Log.tag(VideoPlayer.class);
|
||||
|
||||
private final PlayerView exoView;
|
||||
private final PlayerControlView exoControls;
|
||||
private final DefaultMediaSourceFactory mediaSourceFactory;
|
||||
|
||||
private ExoPlayer exoPlayer;
|
||||
private PlayerControlView exoControls;
|
||||
private Window window;
|
||||
private PlayerStateCallback playerStateCallback;
|
||||
private PlayerPositionDiscontinuityCallback playerPositionDiscontinuityCallback;
|
||||
|
@ -233,6 +231,11 @@ public class VideoPlayer extends FrameLayout {
|
|||
return this.exoControls;
|
||||
}
|
||||
|
||||
public void setControlView(MediaPreviewPlayerControlView controller) {
|
||||
exoControls = controller;
|
||||
exoControls.setPlayer(exoPlayer);
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
if (this.exoPlayer != null) {
|
||||
exoPlayer.stop();
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="12dp"
|
||||
android:height="12dp"
|
||||
android:viewportWidth="12"
|
||||
android:viewportHeight="12">
|
||||
<path
|
||||
android:pathData="M4.513,10.8L3.875,10.164L8.029,6L3.875,1.835L4.513,1.2L9.3,6L4.513,10.8Z"
|
||||
android:fillColor="@color/core_white"/>
|
||||
</vector>
|
|
@ -0,0 +1,9 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:pathData="M4,20.5H20V22H4V20.5ZM20.65,10.35L12,19L3.35,10.35C3.281,10.28 3.234,10.19 3.216,10.093C3.197,9.996 3.208,9.896 3.247,9.805C3.285,9.714 3.35,9.637 3.432,9.582C3.515,9.528 3.611,9.499 3.71,9.5H8V3H16V9.5H20.29C21,9.5 21.12,9.88 20.65,10.35ZM17.88,11H14.5V4.5H9.5V11H6.12L12,16.88L17.88,11Z"
|
||||
android:fillColor="#000000"/>
|
||||
</vector>
|
|
@ -0,0 +1,9 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:pathData="M15.622,8.813C16.688,8.813 17.59,8.126 17.939,7.183H21.487C21.907,7.183 22.276,6.813 22.276,6.352C22.276,5.891 21.907,5.532 21.487,5.532H17.939C17.601,4.578 16.688,3.881 15.622,3.881C14.555,3.881 13.632,4.578 13.294,5.532H2.435C1.974,5.532 1.615,5.891 1.615,6.352C1.615,6.813 1.974,7.183 2.435,7.183H13.304C13.643,8.126 14.555,8.813 15.622,8.813ZM15.622,7.552C14.945,7.552 14.422,7.019 14.422,6.342C14.422,5.665 14.945,5.142 15.622,5.142C16.298,5.142 16.821,5.665 16.821,6.342C16.821,7.019 16.298,7.552 15.622,7.552ZM2.394,11.787C1.974,11.787 1.615,12.156 1.615,12.617C1.615,13.079 1.974,13.438 2.394,13.438H6.065C6.403,14.401 7.316,15.088 8.382,15.088C9.449,15.088 10.361,14.401 10.71,13.438H21.446C21.907,13.438 22.276,13.079 22.276,12.617C22.276,12.156 21.907,11.787 21.446,11.787H10.7C10.361,10.843 9.449,10.156 8.382,10.156C7.316,10.156 6.403,10.843 6.065,11.787H2.394ZM8.382,13.817C7.716,13.817 7.183,13.284 7.183,12.617C7.183,11.94 7.716,11.417 8.382,11.417C9.059,11.417 9.582,11.94 9.582,12.617C9.582,13.284 9.059,13.817 8.382,13.817ZM15.622,21.343C16.688,21.343 17.601,20.656 17.939,19.703H21.487C21.907,19.703 22.276,19.344 22.276,18.882C22.276,18.421 21.907,18.052 21.487,18.052H17.939C17.601,17.098 16.688,16.421 15.622,16.421C14.555,16.421 13.643,17.098 13.304,18.052H2.435C1.974,18.052 1.615,18.421 1.615,18.882C1.615,19.344 1.974,19.703 2.435,19.703H13.294C13.643,20.656 14.555,21.343 15.622,21.343ZM15.622,20.082C14.945,20.082 14.422,19.549 14.422,18.882C14.422,18.195 14.945,17.683 15.622,17.683C16.298,17.683 16.821,18.195 16.821,18.882C16.821,19.549 16.298,20.082 15.622,20.082Z"
|
||||
android:fillColor="#000000"/>
|
||||
</vector>
|
|
@ -0,0 +1,9 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:pathData="M14.521,5.621V9.321L13.212,9.49C11.119,9.672 9.123,10.452 7.462,11.738C5.801,13.025 4.546,14.762 3.847,16.743C3.687,17.149 3.047,18.499 3.047,18.499C3.516,18.041 4.007,17.607 4.52,17.199C7.039,15.597 9.926,14.668 12.906,14.5L14.521,14.376V18.376L20.9,12L14.521,5.621ZM13.384,2.584C13.576,2.608 13.751,2.704 13.874,2.854L22.667,11.646C22.714,11.692 22.75,11.748 22.776,11.808C22.801,11.869 22.814,11.934 22.814,12C22.814,12.066 22.801,12.131 22.776,12.192C22.75,12.252 22.714,12.307 22.667,12.354L13.874,21.146C13.751,21.295 13.576,21.392 13.384,21.416C13.165,21.416 13.021,21.199 13.021,20.793V16C10.922,16.074 8.863,16.596 6.983,17.532C5.103,18.468 3.445,19.796 2.121,21.426C1.839,21.781 1.607,21.955 1.444,21.955C1.23,21.955 1.139,21.655 1.222,21.055C2.2,14.051 5.757,8.934 13.021,8V3.207C13.021,2.801 13.165,2.584 13.384,2.584V2.584Z"
|
||||
android:fillColor="@color/core_white"/>
|
||||
</vector>
|
|
@ -0,0 +1,15 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:pathData="M8.75,5.433C8.417,5.241 8.417,4.759 8.75,4.567L13.25,1.969C13.583,1.776 14,2.017 14,2.402V4.2C18.565,5.127 22,9.162 22,14C22,19.523 17.523,24 12,24C6.477,24 2,19.523 2,14C2,11.037 3.289,8.374 5.337,6.543L6.4,7.606C4.622,9.164 3.5,11.451 3.5,14C3.5,18.694 7.306,22.5 12,22.5C16.694,22.5 20.5,18.694 20.5,14C20.5,9.994 17.729,6.636 14,5.737V7.598C14,7.983 13.583,8.223 13.25,8.031L8.75,5.433Z"
|
||||
android:fillColor="@color/core_white"/>
|
||||
<path
|
||||
android:pathData="M10.398,11.084V17.5H9.234V12.442L7.691,12.952V12.011L10.266,11.084H10.398Z"
|
||||
android:fillColor="@color/core_white"/>
|
||||
<path
|
||||
android:pathData="M13.523,14.556L12.595,14.332L12.951,11.102H16.472V12.064H13.914L13.747,13.558C13.838,13.502 13.97,13.447 14.142,13.391C14.318,13.333 14.516,13.303 14.736,13.303C15.04,13.303 15.313,13.353 15.553,13.453C15.793,13.549 15.997,13.69 16.164,13.875C16.334,14.059 16.461,14.285 16.546,14.551C16.634,14.815 16.678,15.114 16.678,15.448C16.678,15.741 16.634,16.016 16.546,16.274C16.461,16.529 16.331,16.756 16.155,16.955C15.979,17.151 15.758,17.307 15.491,17.421C15.225,17.532 14.911,17.588 14.551,17.588C14.279,17.588 14.016,17.548 13.764,17.469C13.516,17.387 13.291,17.269 13.092,17.113C12.893,16.955 12.733,16.762 12.613,16.533C12.496,16.305 12.432,16.042 12.42,15.747H13.567C13.587,15.943 13.64,16.11 13.725,16.248C13.81,16.385 13.921,16.491 14.059,16.564C14.2,16.637 14.362,16.674 14.547,16.674C14.714,16.674 14.857,16.643 14.977,16.581C15.1,16.517 15.201,16.428 15.281,16.313C15.36,16.199 15.418,16.065 15.456,15.909C15.495,15.754 15.514,15.584 15.514,15.399C15.514,15.221 15.491,15.058 15.448,14.912C15.404,14.762 15.336,14.633 15.245,14.525C15.155,14.417 15.04,14.333 14.903,14.274C14.768,14.216 14.61,14.186 14.428,14.186C14.185,14.186 13.997,14.223 13.866,14.296C13.737,14.37 13.622,14.456 13.523,14.556Z"
|
||||
android:fillColor="@color/core_white"/>
|
||||
</vector>
|
|
@ -0,0 +1,15 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:pathData="M15.25,5.433C15.583,5.241 15.583,4.759 15.25,4.567L10.75,1.969C10.417,1.776 10,2.017 10,2.402V4.2C5.436,5.127 2,9.162 2,14C2,19.523 6.477,24 12,24C17.523,24 22,19.523 22,14C22,11.037 20.711,8.374 18.663,6.543L17.6,7.606C19.378,9.164 20.5,11.451 20.5,14C20.5,18.694 16.694,22.5 12,22.5C7.306,22.5 3.5,18.694 3.5,14C3.5,9.994 6.271,6.636 10,5.737V7.598C10,7.983 10.417,8.223 10.75,8.031L15.25,5.433Z"
|
||||
android:fillColor="@color/core_white"/>
|
||||
<path
|
||||
android:pathData="M10.398,11.084V17.5H9.234V12.442L7.691,12.952V12.011L10.266,11.084H10.398Z"
|
||||
android:fillColor="@color/core_white"/>
|
||||
<path
|
||||
android:pathData="M13.523,14.556L12.595,14.332L12.951,11.102H16.472V12.064H13.914L13.747,13.558C13.838,13.502 13.97,13.447 14.142,13.391C14.318,13.333 14.516,13.303 14.736,13.303C15.04,13.303 15.313,13.353 15.553,13.453C15.793,13.549 15.997,13.69 16.164,13.875C16.334,14.059 16.461,14.285 16.546,14.551C16.634,14.815 16.678,15.114 16.678,15.448C16.678,15.741 16.634,16.016 16.546,16.274C16.461,16.529 16.331,16.756 16.155,16.955C15.979,17.151 15.758,17.307 15.491,17.421C15.225,17.532 14.911,17.588 14.551,17.588C14.279,17.588 14.016,17.548 13.764,17.469C13.516,17.387 13.291,17.269 13.092,17.113C12.893,16.955 12.733,16.762 12.613,16.533C12.496,16.305 12.432,16.042 12.42,15.747H13.567C13.587,15.943 13.64,16.11 13.725,16.248C13.81,16.385 13.921,16.491 14.059,16.564C14.2,16.637 14.362,16.674 14.547,16.674C14.714,16.674 14.857,16.643 14.977,16.581C15.1,16.517 15.201,16.428 15.281,16.313C15.36,16.199 15.418,16.065 15.456,15.909C15.495,15.754 15.514,15.584 15.514,15.399C15.514,15.221 15.491,15.058 15.448,14.912C15.404,14.762 15.336,14.633 15.245,14.525C15.155,14.417 15.04,14.333 14.903,14.274C14.768,14.216 14.61,14.186 14.428,14.186C14.185,14.186 13.997,14.223 13.866,14.296C13.737,14.37 13.622,14.456 13.523,14.556Z"
|
||||
android:fillColor="@color/core_white"/>
|
||||
</vector>
|
|
@ -0,0 +1,9 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:pathData="M22,4.5H16.35C16.136,3.506 15.587,2.615 14.795,1.976C14.004,1.337 13.017,0.988 12,0.988C10.983,0.988 9.996,1.337 9.205,1.976C8.413,2.615 7.864,3.506 7.65,4.5H2V6H3.5L4.86,20C4.922,20.551 5.184,21.059 5.598,21.428C6.011,21.797 6.546,22.001 7.1,22H16.9C17.454,22.001 17.989,21.797 18.403,21.428C18.816,21.059 19.078,20.551 19.14,20L20.5,6H22V4.5ZM12,2.5C12.619,2.502 13.222,2.695 13.727,3.053C14.232,3.411 14.614,3.916 14.82,4.5H9.18C9.386,3.916 9.768,3.411 10.273,3.053C10.778,2.695 11.381,2.502 12,2.5V2.5ZM17.65,19.83C17.628,20.014 17.54,20.183 17.402,20.307C17.264,20.43 17.085,20.499 16.9,20.5H7.1C6.915,20.499 6.736,20.43 6.598,20.307C6.46,20.183 6.372,20.014 6.35,19.83L5,6H19L17.65,19.83ZM11.25,18V8H12.75V18H11.25ZM14.5,18L15,8H16.5L16,18H14.5ZM8,18L7.5,8H9L9.5,18H8Z"
|
||||
android:fillColor="#000000"/>
|
||||
</vector>
|
|
@ -5,51 +5,69 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="bottom"
|
||||
android:background="#CC000000"
|
||||
android:background="@color/transparent"
|
||||
android:layoutDirection="ltr"
|
||||
android:orientation="vertical"
|
||||
tools:targetApi="28">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/exo_duration_viewgroup"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="4dp"
|
||||
android:layout_marginStart="@dimen/media_preview_video_timestamp_inset"
|
||||
android:layout_marginTop="@dimen/media_preview_bottom_bar_vertical_margin"
|
||||
android:layout_marginEnd="@dimen/media_preview_video_timestamp_inset"
|
||||
android:layout_marginBottom="@dimen/media_preview_bottom_bar_vertical_margin"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:id="@id/exo_position"
|
||||
style="@style/Signal.Text.BodyMedium"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:includeFontPadding="false"
|
||||
android:paddingLeft="4dp"
|
||||
android:paddingRight="4dp"
|
||||
android:textColor="#FFBEBEBE"
|
||||
android:textSize="14sp"
|
||||
android:textStyle="bold" />
|
||||
android:textSize="14sp" />
|
||||
|
||||
<View
|
||||
android:id="@id/exo_progress_placeholder"
|
||||
<com.google.android.exoplayer2.ui.DefaultTimeBar
|
||||
android:id="@id/exo_progress"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="26dp"
|
||||
android:layout_weight="1" />
|
||||
|
||||
<TextView
|
||||
android:id="@id/exo_duration"
|
||||
style="@style/Signal.Text.BodyMedium"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:includeFontPadding="false"
|
||||
android:paddingLeft="4dp"
|
||||
android:paddingRight="4dp"
|
||||
android:textColor="#FFBEBEBE"
|
||||
android:textSize="14sp"
|
||||
android:textStyle="bold" />
|
||||
android:textSize="14sp" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/media_preview_album_rail"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginStart="12dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginEnd="12dp"
|
||||
android:orientation="horizontal"
|
||||
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
||||
tools:layout_height="64dp" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/media_preview_bottom_bar_vertical_margin"
|
||||
android:layout_marginBottom="@dimen/media_preview_bottom_bar_vertical_margin"
|
||||
android:gravity="center"
|
||||
android:orientation="horizontal"
|
||||
android:paddingTop="4dp">
|
||||
|
@ -66,41 +84,53 @@
|
|||
android:layout_height="0dp"
|
||||
android:layout_weight="1.0" />
|
||||
|
||||
<ImageButton
|
||||
android:id="@id/exo_prev"
|
||||
style="@style/ExoMediaButton.Previous" />
|
||||
<LinearLayout
|
||||
android:id="@+id/exo_button_viewgroup"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<ImageButton
|
||||
android:id="@id/exo_rew"
|
||||
style="@style/ExoMediaButton.Rewind" />
|
||||
<ImageButton
|
||||
android:id="@id/exo_prev"
|
||||
style="@style/ExoMediaButton.Previous" />
|
||||
|
||||
<ImageButton
|
||||
android:id="@id/exo_shuffle"
|
||||
style="@style/ExoMediaButton" />
|
||||
<ImageButton
|
||||
android:id="@id/exo_rew"
|
||||
style="@style/ExoMediaButton"
|
||||
android:contentDescription="@string/exo_controls_rewind_description"
|
||||
app:srcCompat="@drawable/ic_media_skipback_outline_24" />
|
||||
|
||||
<ImageButton
|
||||
android:id="@id/exo_repeat_toggle"
|
||||
style="@style/ExoMediaButton" />
|
||||
<ImageButton
|
||||
android:id="@id/exo_shuffle"
|
||||
style="@style/ExoMediaButton" />
|
||||
|
||||
<ImageButton
|
||||
android:id="@id/exo_play"
|
||||
style="@style/ExoMediaButton.Play" />
|
||||
<ImageButton
|
||||
android:id="@id/exo_repeat_toggle"
|
||||
style="@style/ExoMediaButton" />
|
||||
|
||||
<ImageButton
|
||||
android:id="@id/exo_pause"
|
||||
style="@style/ExoMediaButton.Pause" />
|
||||
<ImageButton
|
||||
android:id="@id/exo_play"
|
||||
style="@style/ExoMediaButton.Play" />
|
||||
|
||||
<ImageButton
|
||||
android:id="@id/exo_ffwd"
|
||||
style="@style/ExoMediaButton.FastForward" />
|
||||
<ImageButton
|
||||
android:id="@id/exo_pause"
|
||||
style="@style/ExoMediaButton.Pause" />
|
||||
|
||||
<ImageButton
|
||||
android:id="@id/exo_next"
|
||||
style="@style/ExoMediaButton.Next" />
|
||||
<ImageButton
|
||||
android:id="@id/exo_ffwd"
|
||||
style="@style/ExoMediaButton"
|
||||
android:contentDescription="@string/exo_controls_fastforward_description"
|
||||
app:srcCompat="@drawable/ic_media_skipforward_outline_24" />
|
||||
|
||||
<ImageButton
|
||||
android:id="@id/exo_vr"
|
||||
style="@style/ExoMediaButton.VR" />
|
||||
<ImageButton
|
||||
android:id="@id/exo_next"
|
||||
style="@style/ExoMediaButton.Next" />
|
||||
|
||||
<ImageButton
|
||||
android:id="@id/exo_vr"
|
||||
style="@style/ExoMediaButton.VR" />
|
||||
</LinearLayout>
|
||||
|
||||
<Space
|
||||
android:layout_width="0dp"
|
||||
|
@ -112,7 +142,7 @@
|
|||
android:layout_width="@dimen/exo_media_button_width"
|
||||
android:layout_height="@dimen/exo_media_button_height"
|
||||
android:background="?selectableItemBackground"
|
||||
app:srcCompat="@drawable/ic_forward_24" />
|
||||
app:srcCompat="@drawable/ic_forward_outline_24" />
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:background="@color/signal_dark_colorNeutral">
|
||||
android:background="@color/signal_dark_colorSurface">
|
||||
|
||||
<androidx.viewpager2.widget.ViewPager2
|
||||
android:id="@+id/media_pager"
|
||||
android:layout_width="match_parent"
|
||||
|
@ -18,45 +19,37 @@
|
|||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="bottom"
|
||||
android:animateLayoutChanges="true"
|
||||
android:background="@drawable/image_preview_shade"
|
||||
android:background="@color/signal_dark_colorSurface_87"
|
||||
android:gravity="bottom"
|
||||
android:orientation="vertical"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible">
|
||||
|
||||
<org.thoughtcrime.securesms.components.emoji.EmojiTextView
|
||||
android:id="@+id/media_preview_caption"
|
||||
style="@style/Signal.Text.Body"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="bottom"
|
||||
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." />
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/media_preview_album_rail"
|
||||
<org.thoughtcrime.securesms.mediapreview.MediaPreviewPlayerControlView
|
||||
android:id="@+id/media_preview_playback_controls"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginStart="12dp"
|
||||
android:layout_marginEnd="12dp"
|
||||
tools:layout_height="64dp"/>
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/media_preview_playback_controls_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:animateLayoutChanges="true"/>
|
||||
android:animateLayoutChanges="true"
|
||||
android:background="@color/transparent" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<com.google.android.material.appbar.AppBarLayout
|
||||
android:id="@+id/toolbar_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@color/media_preview_bar_background"
|
||||
android:background="@color/signal_dark_colorSurface_87"
|
||||
app:elevation="0dp">
|
||||
|
||||
<View
|
||||
|
@ -67,10 +60,10 @@
|
|||
|
||||
<com.google.android.material.appbar.MaterialToolbar
|
||||
android:id="@+id/toolbar"
|
||||
android:theme="?actionBarStyle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?attr/actionBarSize"
|
||||
android:background="@android:color/transparent"
|
||||
android:theme="?actionBarStyle"
|
||||
app:navigationIcon="@drawable/ic_arrow_left_white_24" />
|
||||
|
||||
</com.google.android.material.appbar.AppBarLayout>
|
||||
|
|
|
@ -1,40 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="bottom"
|
||||
android:background="#CC000000"
|
||||
android:layoutDirection="ltr"
|
||||
android:orientation="vertical"
|
||||
tools:targetApi="28">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="4dp"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/image_preview_share"
|
||||
android:layout_width="@dimen/exo_media_button_width"
|
||||
android:layout_height="@dimen/exo_media_button_height"
|
||||
android:background="?selectableItemBackground"
|
||||
app:srcCompat="@drawable/ic_share_24_outline_white" />
|
||||
|
||||
<Space
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1.0" />
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/image_preview_forward"
|
||||
android:layout_width="@dimen/exo_media_button_width"
|
||||
android:layout_height="@dimen/exo_media_button_height"
|
||||
android:background="?selectableItemBackground"
|
||||
app:srcCompat="@drawable/ic_forward_24" />
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
|
@ -235,4 +235,6 @@
|
|||
<dimen name="stories_landing_item_thumb_outline_width">52dp</dimen>
|
||||
<dimen name="stories_landing_item_thumb_outline_height">76dp</dimen>
|
||||
<dimen name="stories_landing_item_text_horizontal_margin">20dp</dimen>
|
||||
<dimen name="media_preview_video_timestamp_inset">24dp</dimen>
|
||||
<dimen name="media_preview_bottom_bar_vertical_margin">20dp</dimen>
|
||||
</resources>
|
||||
|
|
|
@ -43,5 +43,6 @@
|
|||
<color name="signal_dark_colorNeutralVariantInverse">#A3FFFFFF</color>
|
||||
|
||||
<color name="signal_dark_colorBackground_92">#EB1B1C1F</color>
|
||||
<color name="signal_dark_colorSurface_87">#DE1B1C1F</color>
|
||||
<color name="signal_dark_colorSurfaceVariant_92">#EB303133</color>
|
||||
</resources>
|
Ładowanie…
Reference in New Issue