diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/settings/conversation/ConversationSettingsFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/components/settings/conversation/ConversationSettingsFragment.kt index 14e71ef18..ac6ed5abb 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/settings/conversation/ConversationSettingsFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/components/settings/conversation/ConversationSettingsFragment.kt @@ -513,7 +513,7 @@ class ConversationSettingsFragment : DSLSettingsFragment( mediaIds = state.sharedMediaIds, onMediaRecordClick = { mediaRecord, isLtr -> startActivityForResult( - MediaIntentFactory.intentFromMediaRecord(requireContext(), mediaRecord, isLtr), + MediaIntentFactory.intentFromMediaRecord(requireContext(), mediaRecord, isLtr, allMediaInRail = true), REQUEST_CODE_RETURN_FROM_MEDIA ) } diff --git a/app/src/main/java/org/thoughtcrime/securesms/mediapreview/MediaIntentFactory.kt b/app/src/main/java/org/thoughtcrime/securesms/mediapreview/MediaIntentFactory.kt index 517babc65..d97ded2de 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/mediapreview/MediaIntentFactory.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/mediapreview/MediaIntentFactory.kt @@ -52,7 +52,8 @@ object MediaIntentFactory { fun intentFromMediaRecord( context: Context, mediaRecord: MediaRecord, - leftIsRecent: Boolean + leftIsRecent: Boolean, + allMediaInRail: Boolean ): Intent { val attachment: DatabaseAttachment = mediaRecord.attachment!! return create( @@ -65,7 +66,7 @@ object MediaIntentFactory { attachment.size, attachment.caption, leftIsRecent, - allMediaInRail = true, + allMediaInRail = allMediaInRail, sorting = MediaDatabase.Sorting.Newest, isVideoGif = attachment.isVideoGif ) diff --git a/app/src/main/java/org/thoughtcrime/securesms/mediapreview/MediaPreviewV2Adapter.kt b/app/src/main/java/org/thoughtcrime/securesms/mediapreview/MediaPreviewV2Adapter.kt index 13ad4207c..8fb3f7407 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/mediapreview/MediaPreviewV2Adapter.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/mediapreview/MediaPreviewV2Adapter.kt @@ -4,6 +4,7 @@ import androidx.core.os.bundleOf import androidx.fragment.app.Fragment import androidx.viewpager2.adapter.FragmentStateAdapter import org.thoughtcrime.securesms.attachments.Attachment +import org.thoughtcrime.securesms.mediasend.Media import org.thoughtcrime.securesms.util.MediaUtil class MediaPreviewV2Adapter(val fragment: Fragment) : FragmentStateAdapter(fragment) { @@ -37,6 +38,10 @@ class MediaPreviewV2Adapter(val fragment: Fragment) : FragmentStateAdapter(fragm return fragment } + fun findItemPosition(media: Media): Int { + return items.indexOfFirst { it.uri == media.uri } + } + fun updateBackingItems(newItems: Collection) { if (newItems != items) { items = newItems.toList() diff --git a/app/src/main/java/org/thoughtcrime/securesms/mediapreview/MediaPreviewV2Fragment.kt b/app/src/main/java/org/thoughtcrime/securesms/mediapreview/MediaPreviewV2Fragment.kt index 6faa0a6fa..550d8af46 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/mediapreview/MediaPreviewV2Fragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/mediapreview/MediaPreviewV2Fragment.kt @@ -24,7 +24,8 @@ import androidx.core.view.WindowInsetsCompat import androidx.core.view.isVisible import androidx.fragment.app.Fragment import androidx.fragment.app.viewModels -import androidx.recyclerview.widget.PagerSnapHelper +import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.LinearSmoothScroller import androidx.recyclerview.widget.RecyclerView import androidx.viewpager2.widget.MarginPageTransformer import androidx.viewpager2.widget.ViewPager2.OFFSCREEN_PAGE_LIMIT_DEFAULT @@ -42,7 +43,9 @@ import org.thoughtcrime.securesms.conversation.mutiselect.forward.MultiselectFor import org.thoughtcrime.securesms.conversation.mutiselect.forward.MultiselectForwardFragmentArgs import org.thoughtcrime.securesms.database.MediaDatabase import org.thoughtcrime.securesms.databinding.FragmentMediaPreviewV2Binding -import org.thoughtcrime.securesms.mediapreview.MediaRailAdapter.ImageLoadingListener +import org.thoughtcrime.securesms.mediapreview.mediarail.CenterDecoration +import org.thoughtcrime.securesms.mediapreview.mediarail.MediaRailAdapter +import org.thoughtcrime.securesms.mediapreview.mediarail.MediaRailAdapter.ImageLoadingListener import org.thoughtcrime.securesms.mediasend.Media import org.thoughtcrime.securesms.mediasend.v2.MediaSelectionActivity import org.thoughtcrime.securesms.mms.GlideApp @@ -137,20 +140,11 @@ class MediaPreviewV2Fragment : Fragment(R.layout.fragment_media_preview_v2), Med private fun initializeAlbumRail() { binding.mediaPreviewPlaybackControls.recyclerView.apply { - this.itemAnimator = null // Or can crash when set to INVISIBLE while animating by FullscreenHelper https://issuetracker.google.com/issues/148720682 - PagerSnapHelper().attachToRecyclerView(this) + layoutManager = LinearLayoutManager(requireContext(), LinearLayoutManager.HORIZONTAL, false) + addItemDecoration(CenterDecoration(0)) albumRailAdapter = MediaRailAdapter( GlideApp.with(this@MediaPreviewV2Fragment), - object : MediaRailAdapter.RailItemListener { - override fun onRailItemClicked(distanceFromActive: Int) { - binding.mediaPager.currentItem += distanceFromActive - } - - override fun onRailItemDeleteClicked(distanceFromActive: Int) { - throw UnsupportedOperationException("Callback unsupported.") - } - }, - false, + { media -> jumpViewPagerToMedia(media) }, object : ImageLoadingListener() { override fun onAllRequestsFinished() { crossfadeViewIn(this@apply) @@ -281,14 +275,40 @@ class MediaPreviewV2Fragment : Fragment(R.layout.fragment_media_preview_v2), Med if (albumRail.visibility == GONE) { albumRail.visibility = View.INVISIBLE } - albumRailAdapter.setMedia(albumThumbnailMedia, albumPosition) - albumRail.smoothScrollToPosition(albumPosition) + + albumRailAdapter.currentItemPosition = albumPosition + albumRailAdapter.submitList(albumThumbnailMedia) + scrollAlbumRailToCurrentAdapterPosition() } else { albumRail.visibility = View.GONE - albumRailAdapter.setMedia(emptyList()) + albumRailAdapter.submitList(emptyList()) + albumRailAdapter.imageLoadingListener.reset() } } + private fun scrollAlbumRailToCurrentAdapterPosition() { + val currentItemPosition = albumRailAdapter.currentItemPosition + val currentList = albumRailAdapter.currentList + val albumRail: RecyclerView = binding.mediaPreviewPlaybackControls.recyclerView + var selectedItemWidth = -1 + for (i in currentList.indices) { + val isSelected = i == currentItemPosition + val stableId = albumRailAdapter.getItemId(i) + val viewHolder = albumRail.findViewHolderForItemId(stableId) as? MediaRailAdapter.MediaRailViewHolder + if (viewHolder != null) { + viewHolder.setSelectedItem(isSelected) + if (isSelected) { + selectedItemWidth = viewHolder.itemView.width + } + } + } + val offsetFromStart = (albumRail.width - selectedItemWidth) / 2 + val smoothScroller = OffsetSmoothScroller(requireContext(), offsetFromStart) + smoothScroller.targetPosition = currentItemPosition + val layoutManager = albumRail.layoutManager as LinearLayoutManager + layoutManager.startSmoothScroll(smoothScroller) + } + private fun crossfadeViewIn(view: View, duration: Long = 200) { if (!view.isVisible) { val viewPropertyAnimator = view.animate() @@ -297,6 +317,11 @@ class MediaPreviewV2Fragment : Fragment(R.layout.fragment_media_preview_v2), Med .withStartAction { view.visibility = VISIBLE } + .withEndAction { + if (view == binding.mediaPreviewPlaybackControls.recyclerView) { + scrollAlbumRailToCurrentAdapterPosition() + } + } if (Build.VERSION.SDK_INT >= 21) { viewPropertyAnimator.interpolator = PathInterpolator(0.17f, 0.17f, 0f, 1f) } @@ -306,6 +331,12 @@ class MediaPreviewV2Fragment : Fragment(R.layout.fragment_media_preview_v2), Med private fun getMediaPreviewFragmentFromChildFragmentManager(currentPosition: Int) = childFragmentManager.findFragmentByTag("f$currentPosition") as? MediaPreviewFragment + private fun jumpViewPagerToMedia(media: Media) { + val viewPagerAdapter = binding.mediaPager.adapter as MediaPreviewV2Adapter + val position = viewPagerAdapter.findItemPosition(media) + binding.mediaPager.setCurrentItem(position, true) + } + private fun getTitleText(mediaRecord: MediaDatabase.MediaRecord, showThread: Boolean): String { val recipient: Recipient = Recipient.live(mediaRecord.recipientId).get() val defaultFromString: String = if (mediaRecord.isOutgoing) { @@ -482,6 +513,16 @@ class MediaPreviewV2Fragment : Fragment(R.layout.fragment_media_preview_v2), Med viewModel.onDestroyView() } + private class OffsetSmoothScroller(context: Context, val offset: Int) : LinearSmoothScroller(context) { + override fun getHorizontalSnapPreference(): Int { + return SNAP_TO_START + } + + override fun calculateDxToMakeVisible(view: View?, snapPreference: Int): Int { + return offset + super.calculateDxToMakeVisible(view, snapPreference) + } + } + companion object { const val ARGS_KEY: String = "args" diff --git a/app/src/main/java/org/thoughtcrime/securesms/mediapreview/MediaRailAdapter.java b/app/src/main/java/org/thoughtcrime/securesms/mediapreview/MediaRailAdapter.java deleted file mode 100644 index fab5bebd1..000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/mediapreview/MediaRailAdapter.java +++ /dev/null @@ -1,249 +0,0 @@ -package org.thoughtcrime.securesms.mediapreview; - -import android.graphics.drawable.Drawable; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.recyclerview.widget.RecyclerView; - -import com.bumptech.glide.load.DataSource; -import com.bumptech.glide.load.engine.GlideException; -import com.bumptech.glide.request.RequestListener; -import com.bumptech.glide.request.target.Target; - -import org.thoughtcrime.securesms.R; -import org.thoughtcrime.securesms.components.ThumbnailView; -import org.thoughtcrime.securesms.mediasend.Media; -import org.thoughtcrime.securesms.mms.GlideRequests; -import org.thoughtcrime.securesms.util.adapter.StableIdGenerator; - -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.atomic.AtomicInteger; - -public class MediaRailAdapter extends RecyclerView.Adapter { - - private static final int TYPE_MEDIA = 1; - private static final int TYPE_BUTTON = 2; - - private final GlideRequests glideRequests; - private final List media; - private final RailItemListener listener; - private final StableIdGenerator stableIdGenerator; - private final ImageLoadingListener imageLoadingListener; - - private RailItemAddListener addListener; - private int activePosition; - private boolean editable; - private boolean interactive; - - public MediaRailAdapter(@NonNull GlideRequests glideRequests, @NonNull RailItemListener listener, boolean editable, ImageLoadingListener imageLoadingListener) { - this.glideRequests = glideRequests; - this.media = new ArrayList<>(); - this.listener = listener; - this.editable = editable; - this.stableIdGenerator = new StableIdGenerator<>(); - this.interactive = true; - this.imageLoadingListener = imageLoadingListener; - - setHasStableIds(true); - } - - @NonNull - @Override - public MediaRailViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int type) { - switch (type) { - case TYPE_MEDIA: - return new MediaViewHolder(LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.mediarail_media_item, viewGroup, false)); - case TYPE_BUTTON: - return new ButtonViewHolder(LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.mediarail_button_item, viewGroup, false)); - default: - throw new UnsupportedOperationException("Unsupported view type: " + type); - } - } - - @Override - public void onBindViewHolder(@NonNull MediaRailViewHolder viewHolder, int i) { - switch (getItemViewType(i)) { - case TYPE_MEDIA: - ((MediaViewHolder) viewHolder).bind(media.get(i), i == activePosition, glideRequests, listener, i - activePosition, editable, interactive, imageLoadingListener); - break; - case TYPE_BUTTON: - ((ButtonViewHolder) viewHolder).bind(addListener); - break; - default: - throw new UnsupportedOperationException("Unsupported view type: " + getItemViewType(i)); - } - } - - @Override - public int getItemViewType(int position) { - if (editable && position == getItemCount() - 1) { - return TYPE_BUTTON; - } else { - return TYPE_MEDIA; - } - } - - @Override - public void onViewRecycled(@NonNull MediaRailViewHolder holder) { - holder.recycle(); - } - - @Override - public int getItemCount() { - return editable ? media.size() + 1 : media.size(); - } - - @Override - public long getItemId(int position) { - switch (getItemViewType(position)) { - case TYPE_MEDIA: - return stableIdGenerator.getId(media.get(position)); - case TYPE_BUTTON: - return Long.MAX_VALUE; - default: - throw new UnsupportedOperationException("Unsupported view type: " + getItemViewType(position)); - } - } - - public void setMedia(@NonNull List media) { - setMedia(media, activePosition); - } - - public void setMedia(@NonNull List records, int activePosition) { - this.activePosition = activePosition; - - this.media.clear(); - this.media.addAll(records); - - notifyDataSetChanged(); - } - - public void setActivePosition(int activePosition) { - this.activePosition = activePosition; - notifyDataSetChanged(); - } - - public void setAddButtonListener(@Nullable RailItemAddListener addListener) { - this.addListener = addListener; - notifyDataSetChanged(); - } - - public void setEditable(boolean editable) { - this.editable = editable; - notifyDataSetChanged(); - } - - public void setInteractive(boolean interactive) { - this.interactive = interactive; - notifyDataSetChanged(); - } - - static abstract class MediaRailViewHolder extends RecyclerView.ViewHolder { - public MediaRailViewHolder(@NonNull View itemView) { - super(itemView); - } - - abstract void recycle(); - } - - static class MediaViewHolder extends MediaRailViewHolder { - - private final ThumbnailView image; - private final View outline; - private final View deleteButton; - private final View captionIndicator; - - MediaViewHolder(@NonNull View itemView) { - super(itemView); - image = itemView.findViewById(R.id.rail_item_image); - outline = itemView.findViewById(R.id.rail_item_outline); - deleteButton = itemView.findViewById(R.id.rail_item_delete); - captionIndicator = itemView.findViewById(R.id.rail_item_caption); - } - - void bind(@NonNull Media media, boolean isActive, @NonNull GlideRequests glideRequests, - @NonNull RailItemListener railItemListener, int distanceFromActive, boolean editable, - boolean interactive, @NonNull ImageLoadingListener listener) - { - listener.onRequest(); - image.setImageResource(glideRequests, media.getUri(), 0, 0, false, listener); - image.setOnClickListener(v -> railItemListener.onRailItemClicked(distanceFromActive)); - - outline.setVisibility(isActive && interactive ? View.VISIBLE : View.GONE); - - captionIndicator.setVisibility(media.getCaption().isPresent() ? View.VISIBLE : View.GONE); - - if (editable && isActive && interactive) { - deleteButton.setVisibility(View.VISIBLE); - deleteButton.setOnClickListener(v -> railItemListener.onRailItemDeleteClicked(distanceFromActive)); - } else { - deleteButton.setVisibility(View.GONE); - } - } - - void recycle() { - image.setOnClickListener(null); - deleteButton.setOnClickListener(null); - } - } - - static class ButtonViewHolder extends MediaRailViewHolder { - - public ButtonViewHolder(@NonNull View itemView) { - super(itemView); - } - - void bind(@Nullable RailItemAddListener addListener) { - if (addListener != null) { - itemView.setOnClickListener(v -> addListener.onRailItemAddClicked()); - } - } - - @Override - void recycle() { - itemView.setOnClickListener(null); - } - } - - public interface RailItemListener { - void onRailItemClicked(int distanceFromActive); - void onRailItemDeleteClicked(int distanceFromActive); - } - - public interface RailItemAddListener { - void onRailItemAddClicked(); - } - - abstract static class ImageLoadingListener implements RequestListener { - final private AtomicInteger activeJobs = new AtomicInteger(); - - void onRequest() { - activeJobs.incrementAndGet(); - } - - @Override - public boolean onLoadFailed(@Nullable GlideException e, Object model, Target target, boolean isFirstResource) { - int count = activeJobs.decrementAndGet(); - if (count == 0) { - onAllRequestsFinished(); - } - return false; - } - - @Override - public boolean onResourceReady(Drawable resource, Object model, Target target, DataSource dataSource, boolean isFirstResource) { - int count = activeJobs.decrementAndGet(); - if (count == 0) { - onAllRequestsFinished(); - } - return false; - } - - abstract void onAllRequestsFinished(); - } -} diff --git a/app/src/main/java/org/thoughtcrime/securesms/mediapreview/mediarail/CenterDecoration.kt b/app/src/main/java/org/thoughtcrime/securesms/mediapreview/mediarail/CenterDecoration.kt new file mode 100644 index 000000000..81fcc0984 --- /dev/null +++ b/app/src/main/java/org/thoughtcrime/securesms/mediapreview/mediarail/CenterDecoration.kt @@ -0,0 +1,45 @@ +package org.thoughtcrime.securesms.mediapreview.mediarail + +import android.graphics.Rect +import android.view.View +import androidx.annotation.Px +import androidx.core.view.doOnPreDraw +import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.RecyclerView + +/** + * From: https://stackoverflow.com/a/53510142 + */ +class CenterDecoration(@Px private val spacing: Int) : RecyclerView.ItemDecoration() { + + private var firstViewWidth = -1 + private var lastViewWidth = -1 + + override fun getItemOffsets(outRect: Rect, view: View, parent: RecyclerView, state: RecyclerView.State) { + super.getItemOffsets(outRect, view, parent, state) + val adapterPosition = (view.layoutParams as RecyclerView.LayoutParams).absoluteAdapterPosition + val layoutManager = parent.layoutManager as LinearLayoutManager + if (adapterPosition == 0) { + if (view.width != firstViewWidth) { + view.doOnPreDraw { parent.invalidateItemDecorations() } + } + firstViewWidth = view.width + outRect.left = parent.width / 2 - view.width / 2 + if (layoutManager.itemCount > 1) { + outRect.right = spacing / 2 + } else { + outRect.right = outRect.left + } + } else if (adapterPosition == layoutManager.itemCount - 1) { + if (view.width != lastViewWidth) { + view.doOnPreDraw { parent.invalidateItemDecorations() } + } + lastViewWidth = view.width + outRect.right = parent.width / 2 - view.width / 2 + outRect.left = spacing / 2 + } else { + outRect.left = spacing / 2 + outRect.right = spacing / 2 + } + } +} diff --git a/app/src/main/java/org/thoughtcrime/securesms/mediapreview/mediarail/MediaRailAdapter.kt b/app/src/main/java/org/thoughtcrime/securesms/mediapreview/mediarail/MediaRailAdapter.kt new file mode 100644 index 000000000..66dcb0909 --- /dev/null +++ b/app/src/main/java/org/thoughtcrime/securesms/mediapreview/mediarail/MediaRailAdapter.kt @@ -0,0 +1,132 @@ +package org.thoughtcrime.securesms.mediapreview.mediarail + +import android.graphics.drawable.Drawable +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.recyclerview.widget.DiffUtil +import androidx.recyclerview.widget.ListAdapter +import androidx.recyclerview.widget.RecyclerView +import com.bumptech.glide.load.DataSource +import com.bumptech.glide.load.engine.GlideException +import com.bumptech.glide.request.RequestListener +import com.bumptech.glide.request.target.Target +import org.thoughtcrime.securesms.R +import org.thoughtcrime.securesms.components.ThumbnailView +import org.thoughtcrime.securesms.mediasend.Media +import org.thoughtcrime.securesms.mms.GlideRequests +import org.thoughtcrime.securesms.util.adapter.StableIdGenerator +import org.thoughtcrime.securesms.util.visible +import java.util.concurrent.atomic.AtomicInteger + +/** + * This is the RecyclerView.Adapter for the row of thumbnails present in the media viewer screen. + */ +class MediaRailAdapter(private val glideRequests: GlideRequests, listener: RailItemListener, imageLoadingListener: ImageLoadingListener) : ListAdapter(MediaDiffer()) { + val imageLoadingListener: ImageLoadingListener + + var currentItemPosition: Int = -1 + + private val listener: RailItemListener + private val stableIdGenerator: StableIdGenerator + + init { + this.listener = listener + stableIdGenerator = StableIdGenerator() + this.imageLoadingListener = imageLoadingListener + setHasStableIds(true) + } + + override fun onCreateViewHolder(viewGroup: ViewGroup, type: Int): MediaRailViewHolder { + return MediaRailViewHolder(LayoutInflater.from(viewGroup.context).inflate(R.layout.mediarail_media_item, viewGroup, false)) + } + + override fun onBindViewHolder(viewHolder: MediaRailViewHolder, i: Int) { + viewHolder.bind(getItem(i), i == currentItemPosition, glideRequests, listener, imageLoadingListener) + } + + override fun onViewRecycled(holder: MediaRailViewHolder) { + holder.recycle() + } + + override fun getItemId(position: Int): Long { + return stableIdGenerator.getId(getItem(position)) + } + + class MediaRailViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { + private val image: ThumbnailView + private val outline: View + private val captionIndicator: View + + init { + image = itemView.findViewById(R.id.rail_item_image) + outline = itemView.findViewById(R.id.rail_item_outline) + captionIndicator = itemView.findViewById(R.id.rail_item_caption) + } + + fun bind( + media: Media, + isCurrentlySelected: Boolean, + glideRequests: GlideRequests, + railItemListener: RailItemListener, + listener: ImageLoadingListener + ) { + listener.onRequest() + image.setImageResource(glideRequests, media.uri, 0, 0, false, listener) + image.setOnClickListener { railItemListener.onRailItemClicked(media) } + captionIndicator.visibility = if (media.caption.isPresent) View.VISIBLE else View.GONE + setSelectedItem(isCurrentlySelected) + } + + fun recycle() { + image.setOnClickListener(null) + } + + fun setSelectedItem(isActive: Boolean) { + outline.visible = isActive + } + } + + fun interface RailItemListener { + fun onRailItemClicked(media: Media) + } + + abstract class ImageLoadingListener : RequestListener { + private val activeJobs = AtomicInteger() + fun onRequest() { + activeJobs.incrementAndGet() + } + + final override fun onLoadFailed(e: GlideException?, model: Any, target: Target, isFirstResource: Boolean): Boolean { + val count = activeJobs.decrementAndGet() + if (count == 0) { + onAllRequestsFinished() + } + return false + } + + final override fun onResourceReady(resource: Drawable?, model: Any, target: Target, dataSource: DataSource, isFirstResource: Boolean): Boolean { + val count = activeJobs.decrementAndGet() + if (count == 0) { + onAllRequestsFinished() + } + return false + } + + fun reset() { + activeJobs.set(0) + } + + abstract fun onAllRequestsFinished() + } + + class MediaDiffer : DiffUtil.ItemCallback() { + override fun areItemsTheSame(oldItem: Media, newItem: Media): Boolean { + return oldItem.uri == newItem.uri + } + + override fun areContentsTheSame(oldItem: Media, newItem: Media): Boolean { + return oldItem == newItem + } + } +} diff --git a/app/src/main/res/layout/exo_player_control_view.xml b/app/src/main/res/layout/exo_player_control_view.xml index adb085a15..3edacf91d 100644 --- a/app/src/main/res/layout/exo_player_control_view.xml +++ b/app/src/main/res/layout/exo_player_control_view.xml @@ -50,7 +50,7 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/app/src/main/res/layout/mediarail_media_item.xml b/app/src/main/res/layout/mediarail_media_item.xml index e61b3def8..1cfaf8088 100644 --- a/app/src/main/res/layout/mediarail_media_item.xml +++ b/app/src/main/res/layout/mediarail_media_item.xml @@ -4,8 +4,8 @@ tools:viewBindingIgnore="true" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" - android:layout_width="46dp" - android:layout_height="46dp" + android:layout_width="@dimen/media_rail_item_size" + android:layout_height="@dimen/media_rail_item_size" android:layout_margin="4dp" android:animateLayoutChanges="true"> @@ -42,14 +42,4 @@ android:visibility="gone" tools:visibility="visible"/> - - diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml index 1fe036458..51dd3839b 100644 --- a/app/src/main/res/values/dimens.xml +++ b/app/src/main/res/values/dimens.xml @@ -243,4 +243,5 @@ 48dp 8dp 36dp + 46dp