Add PagingMappingAdapter and convert GiphyMp4Adapter.
This commit is contained in:
parent
dd79688f48
commit
5918227bff
6 changed files with 96 additions and 67 deletions
|
@ -9,8 +9,9 @@ import androidx.annotation.Nullable;
|
||||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
|
||||||
import org.thoughtcrime.securesms.util.ByteUnit;
|
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);
|
private static final int MAX_SIZE = (int) ByteUnit.MEGABYTES.toBytes(2);
|
||||||
|
|
||||||
|
@ -20,6 +21,16 @@ public class GiphyImage {
|
||||||
@JsonProperty("is_sticker")
|
@JsonProperty("is_sticker")
|
||||||
private boolean isSticker;
|
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() {
|
public boolean isSticker() {
|
||||||
return isSticker;
|
return isSticker;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,77 +1,24 @@
|
||||||
package org.thoughtcrime.securesms.giph.mp4;
|
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.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
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.R;
|
||||||
import org.thoughtcrime.securesms.giph.model.GiphyImage;
|
import org.thoughtcrime.securesms.giph.model.GiphyImage;
|
||||||
|
import org.thoughtcrime.securesms.util.adapter.mapping.LayoutFactory;
|
||||||
import java.util.Objects;
|
import org.thoughtcrime.securesms.util.adapter.mapping.PagingMappingAdapter;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Maintains and displays a list of GiphyImage objects. This Adapter always displays gifs
|
* Maintains and displays a list of GiphyImage objects. This Adapter always displays gifs
|
||||||
* as MP4 videos.
|
* as MP4 videos.
|
||||||
*/
|
*/
|
||||||
final class GiphyMp4Adapter extends ListAdapter<GiphyImage, GiphyMp4ViewHolder> {
|
final class GiphyMp4Adapter extends PagingMappingAdapter<String> {
|
||||||
|
|
||||||
private final Callback listener;
|
|
||||||
|
|
||||||
private PagingController pagingController;
|
|
||||||
|
|
||||||
public GiphyMp4Adapter(@Nullable Callback listener) {
|
public GiphyMp4Adapter(@Nullable Callback listener) {
|
||||||
super(new GiphyImageDiffUtilCallback());
|
registerFactory(GiphyImage.class, new LayoutFactory<>(v -> new GiphyMp4ViewHolder(v, listener), R.layout.giphy_mp4));
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Callback {
|
interface Callback {
|
||||||
void onClick(@NonNull GiphyImage giphyImage);
|
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
|
@ -9,7 +9,6 @@ import android.widget.ImageView;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
|
||||||
|
|
||||||
import com.bumptech.glide.load.engine.DiskCacheStrategy;
|
import com.bumptech.glide.load.engine.DiskCacheStrategy;
|
||||||
import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions;
|
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.Projection;
|
||||||
import org.thoughtcrime.securesms.util.Util;
|
import org.thoughtcrime.securesms.util.Util;
|
||||||
import org.thoughtcrime.securesms.util.ViewUtil;
|
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.
|
* 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));
|
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);
|
container.setResizeMode(AspectRatioFrameLayout.RESIZE_MODE_FIXED_WIDTH);
|
||||||
}
|
}
|
||||||
|
|
||||||
void onBind(@NonNull GiphyImage giphyImage) {
|
@Override
|
||||||
|
public void bind(@NonNull GiphyImage giphyImage) {
|
||||||
aspectRatio = giphyImage.getGifAspectRatio();
|
aspectRatio = giphyImage.getGifAspectRatio();
|
||||||
mediaItem = MediaItem.fromUri(Uri.parse(giphyImage.getMp4PreviewUrl()));
|
mediaItem = MediaItem.fromUri(Uri.parse(giphyImage.getMp4PreviewUrl()));
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,7 @@ import org.signal.paging.PagingConfig;
|
||||||
import org.signal.paging.PagingController;
|
import org.signal.paging.PagingController;
|
||||||
import org.thoughtcrime.securesms.giph.model.GiphyImage;
|
import org.thoughtcrime.securesms.giph.model.GiphyImage;
|
||||||
import org.thoughtcrime.securesms.util.DefaultValueLiveData;
|
import org.thoughtcrime.securesms.util.DefaultValueLiveData;
|
||||||
|
import org.thoughtcrime.securesms.util.adapter.mapping.MappingModelList;
|
||||||
import org.thoughtcrime.securesms.util.SingleLiveEvent;
|
import org.thoughtcrime.securesms.util.SingleLiveEvent;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -30,7 +31,7 @@ public final class GiphyMp4ViewModel extends ViewModel {
|
||||||
|
|
||||||
private final GiphyMp4Repository repository;
|
private final GiphyMp4Repository repository;
|
||||||
private final MutableLiveData<PagedData<String, GiphyImage>> pagedData;
|
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 LiveData<PagingController<String>> pagingController;
|
||||||
private final SingleLiveEvent<GiphyMp4SaveResult> saveResultEvents;
|
private final SingleLiveEvent<GiphyMp4SaveResult> saveResultEvents;
|
||||||
private final boolean isForMms;
|
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(isForMms ? g.getGifMmsUrl() : g.getGifUrl()))
|
||||||
.filterNot(g -> TextUtils.isEmpty(g.getMp4PreviewUrl()))
|
.filterNot(g -> TextUtils.isEmpty(g.getMp4PreviewUrl()))
|
||||||
.filterNot(g -> TextUtils.isEmpty(g.getStillUrl()))
|
.filterNot(g -> TextUtils.isEmpty(g.getStillUrl()))
|
||||||
.toList()));
|
.collect(MappingModelList.toMappingModelList())));
|
||||||
}
|
}
|
||||||
|
|
||||||
LiveData<PagedData<String, GiphyImage>> getPagedData() {
|
LiveData<PagedData<String, GiphyImage>> getPagedData() {
|
||||||
|
@ -73,7 +74,7 @@ public final class GiphyMp4ViewModel extends ViewModel {
|
||||||
return saveResultEvents;
|
return saveResultEvents;
|
||||||
}
|
}
|
||||||
|
|
||||||
public @NonNull LiveData<List<GiphyImage>> getImages() {
|
public @NonNull LiveData<MappingModelList> getImages() {
|
||||||
return images;
|
return images;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -44,9 +44,9 @@ import kotlin.jvm.functions.Function1;
|
||||||
*/
|
*/
|
||||||
public class MappingAdapter extends ListAdapter<MappingModel<?>, MappingViewHolder<?>> {
|
public class MappingAdapter extends ListAdapter<MappingModel<?>, MappingViewHolder<?>> {
|
||||||
|
|
||||||
private final Map<Integer, Factory<?>> factories;
|
final Map<Integer, Factory<?>> factories;
|
||||||
private final Map<Class<?>, Integer> itemTypes;
|
final Map<Class<?>, Integer> itemTypes;
|
||||||
private int typeCount;
|
int typeCount;
|
||||||
|
|
||||||
public MappingAdapter() {
|
public MappingAdapter() {
|
||||||
super(new MappingDiffCallback());
|
super(new MappingDiffCallback());
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue