Add PagingMappingAdapter and convert GiphyMp4Adapter.

This commit is contained in:
Cody Henthorne 2021-12-16 14:31:01 -05:00 committed by Greyson Parrelli
parent dd79688f48
commit 5918227bff
6 changed files with 96 additions and 67 deletions

View file

@ -9,8 +9,9 @@ import androidx.annotation.Nullable;
import com.fasterxml.jackson.annotation.JsonProperty;
import org.thoughtcrime.securesms.util.ByteUnit;
import org.thoughtcrime.securesms.util.adapter.mapping.MappingModel;
public class GiphyImage {
public class GiphyImage implements MappingModel<GiphyImage> {
private static final int MAX_SIZE = (int) ByteUnit.MEGABYTES.toBytes(2);
@ -20,6 +21,16 @@ public class GiphyImage {
@JsonProperty("is_sticker")
private boolean isSticker;
@Override
public boolean areItemsTheSame(@NonNull GiphyImage newItem) {
return getMp4Url().equals(newItem.getMp4Url());
}
@Override
public boolean areContentsTheSame(@NonNull GiphyImage newItem) {
return areItemsTheSame(newItem);
}
public boolean isSticker() {
return isSticker;
}

View file

@ -1,77 +1,24 @@
package org.thoughtcrime.securesms.giph.mp4;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.recyclerview.widget.DiffUtil;
import androidx.recyclerview.widget.ListAdapter;
import org.signal.paging.PagingController;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.giph.model.GiphyImage;
import java.util.Objects;
import org.thoughtcrime.securesms.util.adapter.mapping.LayoutFactory;
import org.thoughtcrime.securesms.util.adapter.mapping.PagingMappingAdapter;
/**
* Maintains and displays a list of GiphyImage objects. This Adapter always displays gifs
* as MP4 videos.
*/
final class GiphyMp4Adapter extends ListAdapter<GiphyImage, GiphyMp4ViewHolder> {
private final Callback listener;
private PagingController pagingController;
final class GiphyMp4Adapter extends PagingMappingAdapter<String> {
public GiphyMp4Adapter(@Nullable Callback listener) {
super(new GiphyImageDiffUtilCallback());
this.listener = listener;
}
@Override
public @NonNull GiphyMp4ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.giphy_mp4, parent, false);
return new GiphyMp4ViewHolder(itemView, listener);
}
@Override
public void onBindViewHolder(@NonNull GiphyMp4ViewHolder holder, int position) {
holder.onBind(getItem(position));
}
@Override
protected GiphyImage getItem(int position) {
if (pagingController != null) {
pagingController.onDataNeededAroundIndex(position);
}
return super.getItem(position);
}
void setPagingController(@Nullable PagingController pagingController) {
this.pagingController = pagingController;
registerFactory(GiphyImage.class, new LayoutFactory<>(v -> new GiphyMp4ViewHolder(v, listener), R.layout.giphy_mp4));
}
interface Callback {
void onClick(@NonNull GiphyImage giphyImage);
}
private static final class GiphyImageDiffUtilCallback extends DiffUtil.ItemCallback<GiphyImage> {
@Override
public boolean areItemsTheSame(@NonNull GiphyImage oldItem, @NonNull GiphyImage newItem) {
return Objects.equals(oldItem.getMp4Url(), newItem.getMp4Url());
}
@Override
public boolean areContentsTheSame(@NonNull GiphyImage oldItem, @NonNull GiphyImage newItem) {
return areItemsTheSame(oldItem, newItem);
}
}
}

View file

@ -9,7 +9,6 @@ import android.widget.ImageView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.recyclerview.widget.RecyclerView;
import com.bumptech.glide.load.engine.DiskCacheStrategy;
import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions;
@ -24,11 +23,12 @@ import org.thoughtcrime.securesms.mms.GlideApp;
import org.thoughtcrime.securesms.util.Projection;
import org.thoughtcrime.securesms.util.Util;
import org.thoughtcrime.securesms.util.ViewUtil;
import org.thoughtcrime.securesms.util.adapter.mapping.MappingViewHolder;
/**
* Holds a view which will either play back an MP4 gif or show its still.
*/
final class GiphyMp4ViewHolder extends RecyclerView.ViewHolder implements GiphyMp4Playable {
final class GiphyMp4ViewHolder extends MappingViewHolder<GiphyImage> implements GiphyMp4Playable {
private static final Projection.Corners CORNERS = new Projection.Corners(ViewUtil.dpToPx(8));
@ -52,7 +52,8 @@ final class GiphyMp4ViewHolder extends RecyclerView.ViewHolder implements GiphyM
container.setResizeMode(AspectRatioFrameLayout.RESIZE_MODE_FIXED_WIDTH);
}
void onBind(@NonNull GiphyImage giphyImage) {
@Override
public void bind(@NonNull GiphyImage giphyImage) {
aspectRatio = giphyImage.getGifAspectRatio();
mediaItem = MediaItem.fromUri(Uri.parse(giphyImage.getMp4PreviewUrl()));

View file

@ -17,6 +17,7 @@ import org.signal.paging.PagingConfig;
import org.signal.paging.PagingController;
import org.thoughtcrime.securesms.giph.model.GiphyImage;
import org.thoughtcrime.securesms.util.DefaultValueLiveData;
import org.thoughtcrime.securesms.util.adapter.mapping.MappingModelList;
import org.thoughtcrime.securesms.util.SingleLiveEvent;
import java.util.List;
@ -30,7 +31,7 @@ public final class GiphyMp4ViewModel extends ViewModel {
private final GiphyMp4Repository repository;
private final MutableLiveData<PagedData<String, GiphyImage>> pagedData;
private final LiveData<List<GiphyImage>> images;
private final LiveData<MappingModelList> images;
private final LiveData<PagingController<String>> pagingController;
private final SingleLiveEvent<GiphyMp4SaveResult> saveResultEvents;
private final boolean isForMms;
@ -49,7 +50,7 @@ public final class GiphyMp4ViewModel extends ViewModel {
.filterNot(g -> TextUtils.isEmpty(isForMms ? g.getGifMmsUrl() : g.getGifUrl()))
.filterNot(g -> TextUtils.isEmpty(g.getMp4PreviewUrl()))
.filterNot(g -> TextUtils.isEmpty(g.getStillUrl()))
.toList()));
.collect(MappingModelList.toMappingModelList())));
}
LiveData<PagedData<String, GiphyImage>> getPagedData() {
@ -73,7 +74,7 @@ public final class GiphyMp4ViewModel extends ViewModel {
return saveResultEvents;
}
public @NonNull LiveData<List<GiphyImage>> getImages() {
public @NonNull LiveData<MappingModelList> getImages() {
return images;
}

View file

@ -44,9 +44,9 @@ import kotlin.jvm.functions.Function1;
*/
public class MappingAdapter extends ListAdapter<MappingModel<?>, MappingViewHolder<?>> {
private final Map<Integer, Factory<?>> factories;
private final Map<Class<?>, Integer> itemTypes;
private int typeCount;
final Map<Integer, Factory<?>> factories;
final Map<Class<?>, Integer> itemTypes;
int typeCount;
public MappingAdapter() {
super(new MappingDiffCallback());

View file

@ -0,0 +1,69 @@
package org.thoughtcrime.securesms.util.adapter.mapping;
import android.view.View;
import android.widget.FrameLayout;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import org.signal.paging.PagingController;
import org.thoughtcrime.securesms.util.ViewUtil;
/**
* A specialized {@link MappingAdapter} backed by a {@link PagingController}.
*/
public class PagingMappingAdapter<Key> extends MappingAdapter {
private PagingController<Key> pagingController;
public PagingMappingAdapter() {
this(1, ViewUtil.dpToPx(100));
}
public PagingMappingAdapter(int placeHolderWidth, int placeHolderHeight) {
registerFactory(Placeholder.class, parent -> {
View view = new FrameLayout(parent.getContext());
view.setLayoutParams(new FrameLayout.LayoutParams(placeHolderWidth, placeHolderHeight));
return new MappingViewHolder.SimpleViewHolder<>(view);
});
}
public void setPagingController(@Nullable PagingController<Key> pagingController) {
this.pagingController = pagingController;
}
@Override
protected @Nullable MappingModel<?> getItem(int position) {
if (pagingController != null) {
pagingController.onDataNeededAroundIndex(position);
}
return super.getItem(position);
}
@Override
public int getItemViewType(int position) {
MappingModel<?> item = getItem(position);
if (item == null) {
//noinspection ConstantConditions
return itemTypes.get(Placeholder.class);
}
Integer type = itemTypes.get(item.getClass());
if (type != null) {
return type;
}
throw new AssertionError("No view holder factory for type: " + item.getClass());
}
private static class Placeholder implements MappingModel<Placeholder> {
@Override
public boolean areItemsTheSame(@NonNull Placeholder newItem) {
return false;
}
@Override
public boolean areContentsTheSame(@NonNull Placeholder newItem) {
return false;
}
}
}