Media Preview V2 Visual Redesign.

main
Nicholas 2022-10-25 15:22:38 -04:00 zatwierdzone przez Alex Hart
rodzic b8174c5e00
commit 7759ad283d
21 zmienionych plików z 339 dodań i 230 usunięć

Wyświetl plik

@ -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;
}
}

Wyświetl plik

@ -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) {

Wyświetl plik

@ -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)
}

Wyświetl plik

@ -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
}

Wyświetl plik

@ -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"
}

Wyświetl plik

@ -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 }
}

Wyświetl plik

@ -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)
}
}

Wyświetl plik

@ -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() {

Wyświetl plik

@ -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();

Wyświetl plik

@ -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>

Wyświetl plik

@ -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>

Wyświetl plik

@ -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>

Wyświetl plik

@ -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>

Wyświetl plik

@ -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>

Wyświetl plik

@ -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>

Wyświetl plik

@ -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>

Wyświetl plik

@ -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>

Wyświetl plik

@ -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>

Wyświetl plik

@ -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>

Wyświetl plik

@ -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>

Wyświetl plik

@ -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>