|
|
|
|
@@ -29,20 +29,20 @@ import org.joinmastodon.android.model.Poll;
|
|
|
|
|
import org.joinmastodon.android.model.Relationship;
|
|
|
|
|
import org.joinmastodon.android.model.Status;
|
|
|
|
|
import org.joinmastodon.android.ui.BetterItemAnimator;
|
|
|
|
|
import org.joinmastodon.android.ui.PhotoLayoutHelper;
|
|
|
|
|
import org.joinmastodon.android.ui.TileGridLayoutManager;
|
|
|
|
|
import org.joinmastodon.android.ui.displayitems.ExtendedFooterStatusDisplayItem;
|
|
|
|
|
import org.joinmastodon.android.ui.displayitems.GapStatusDisplayItem;
|
|
|
|
|
import org.joinmastodon.android.ui.displayitems.HeaderStatusDisplayItem;
|
|
|
|
|
import org.joinmastodon.android.ui.displayitems.ImageStatusDisplayItem;
|
|
|
|
|
import org.joinmastodon.android.ui.displayitems.MediaGridStatusDisplayItem;
|
|
|
|
|
import org.joinmastodon.android.ui.displayitems.PollFooterStatusDisplayItem;
|
|
|
|
|
import org.joinmastodon.android.ui.displayitems.PollOptionStatusDisplayItem;
|
|
|
|
|
import org.joinmastodon.android.ui.displayitems.StatusDisplayItem;
|
|
|
|
|
import org.joinmastodon.android.ui.displayitems.TextStatusDisplayItem;
|
|
|
|
|
import org.joinmastodon.android.ui.photoviewer.PhotoViewer;
|
|
|
|
|
import org.joinmastodon.android.ui.photoviewer.PhotoViewerHost;
|
|
|
|
|
import org.joinmastodon.android.ui.utils.MediaAttachmentViewController;
|
|
|
|
|
import org.joinmastodon.android.ui.utils.UiUtils;
|
|
|
|
|
import org.joinmastodon.android.ui.views.ImageAttachmentFrameLayout;
|
|
|
|
|
import org.joinmastodon.android.ui.views.MediaGridLayout;
|
|
|
|
|
import org.joinmastodon.android.utils.TypedObjectPool;
|
|
|
|
|
|
|
|
|
|
import java.util.ArrayList;
|
|
|
|
|
import java.util.Collections;
|
|
|
|
|
@@ -53,7 +53,6 @@ import java.util.stream.Collectors;
|
|
|
|
|
|
|
|
|
|
import androidx.annotation.NonNull;
|
|
|
|
|
import androidx.annotation.Nullable;
|
|
|
|
|
import androidx.recyclerview.widget.GridLayoutManager;
|
|
|
|
|
import androidx.recyclerview.widget.RecyclerView;
|
|
|
|
|
import me.grishka.appkit.api.Callback;
|
|
|
|
|
import me.grishka.appkit.api.ErrorResponse;
|
|
|
|
|
@@ -73,6 +72,7 @@ public abstract class BaseStatusListFragment<T extends DisplayItemsParent> exten
|
|
|
|
|
protected HashMap<String, Account> knownAccounts=new HashMap<>();
|
|
|
|
|
protected HashMap<String, Relationship> relationships=new HashMap<>();
|
|
|
|
|
protected Rect tmpRect=new Rect();
|
|
|
|
|
protected TypedObjectPool<MediaGridStatusDisplayItem.GridItemType, MediaAttachmentViewController> attachmentViewsPool=new TypedObjectPool<>(this::makeNewMediaAttachmentView);
|
|
|
|
|
|
|
|
|
|
public BaseStatusListFragment(){
|
|
|
|
|
super(20);
|
|
|
|
|
@@ -171,21 +171,21 @@ public abstract class BaseStatusListFragment<T extends DisplayItemsParent> exten
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public void openPhotoViewer(String parentID, Status _status, int attachmentIndex){
|
|
|
|
|
final Status status=_status.reblog!=null ? _status.reblog : _status;
|
|
|
|
|
public void openPhotoViewer(String parentID, Status _status, int attachmentIndex, MediaGridStatusDisplayItem.Holder gridHolder){
|
|
|
|
|
final Status status=_status.getContentStatus();
|
|
|
|
|
currentPhotoViewer=new PhotoViewer(getActivity(), status.mediaAttachments, attachmentIndex, new PhotoViewer.Listener(){
|
|
|
|
|
private ImageStatusDisplayItem.Holder<?> transitioningHolder;
|
|
|
|
|
private MediaAttachmentViewController transitioningHolder;
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public void setPhotoViewVisibility(int index, boolean visible){
|
|
|
|
|
ImageStatusDisplayItem.Holder<?> holder=findPhotoViewHolder(index);
|
|
|
|
|
MediaAttachmentViewController holder=findPhotoViewHolder(index);
|
|
|
|
|
if(holder!=null)
|
|
|
|
|
holder.photo.setAlpha(visible ? 1f : 0f);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public boolean startPhotoViewTransition(int index, @NonNull Rect outRect, @NonNull int[] outCornerRadius){
|
|
|
|
|
ImageStatusDisplayItem.Holder<?> holder=findPhotoViewHolder(index);
|
|
|
|
|
MediaAttachmentViewController holder=findPhotoViewHolder(index);
|
|
|
|
|
if(holder!=null){
|
|
|
|
|
transitioningHolder=holder;
|
|
|
|
|
View view=transitioningHolder.photo;
|
|
|
|
|
@@ -193,7 +193,8 @@ public abstract class BaseStatusListFragment<T extends DisplayItemsParent> exten
|
|
|
|
|
view.getLocationOnScreen(pos);
|
|
|
|
|
outRect.set(pos[0], pos[1], pos[0]+view.getWidth(), pos[1]+view.getHeight());
|
|
|
|
|
list.setClipChildren(false);
|
|
|
|
|
transitioningHolder.itemView.setElevation(1f);
|
|
|
|
|
gridHolder.setClipChildren(false);
|
|
|
|
|
transitioningHolder.view.setElevation(1f);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
@@ -220,15 +221,16 @@ public abstract class BaseStatusListFragment<T extends DisplayItemsParent> exten
|
|
|
|
|
view.setTranslationY(0f);
|
|
|
|
|
view.setScaleX(1f);
|
|
|
|
|
view.setScaleY(1f);
|
|
|
|
|
transitioningHolder.itemView.setElevation(0f);
|
|
|
|
|
transitioningHolder.view.setElevation(0f);
|
|
|
|
|
if(list!=null)
|
|
|
|
|
list.setClipChildren(true);
|
|
|
|
|
gridHolder.setClipChildren(true);
|
|
|
|
|
transitioningHolder=null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public Drawable getPhotoViewCurrentDrawable(int index){
|
|
|
|
|
ImageStatusDisplayItem.Holder<?> holder=findPhotoViewHolder(index);
|
|
|
|
|
MediaAttachmentViewController holder=findPhotoViewHolder(index);
|
|
|
|
|
if(holder!=null)
|
|
|
|
|
return holder.photo.getDrawable();
|
|
|
|
|
return null;
|
|
|
|
|
@@ -244,23 +246,8 @@ public abstract class BaseStatusListFragment<T extends DisplayItemsParent> exten
|
|
|
|
|
requestPermissions(permissions, PhotoViewer.PERMISSION_REQUEST);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private ImageStatusDisplayItem.Holder<?> findPhotoViewHolder(int index){
|
|
|
|
|
if(list==null)
|
|
|
|
|
return null;
|
|
|
|
|
int offset=0;
|
|
|
|
|
for(StatusDisplayItem item:displayItems){
|
|
|
|
|
if(item.parentID.equals(parentID)){
|
|
|
|
|
if(item instanceof ImageStatusDisplayItem){
|
|
|
|
|
RecyclerView.ViewHolder holder=list.findViewHolderForAdapterPosition(getMainAdapterOffset()+offset+index);
|
|
|
|
|
if(holder instanceof ImageStatusDisplayItem.Holder<?> imgHolder){
|
|
|
|
|
return imgHolder;
|
|
|
|
|
}
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
offset++;
|
|
|
|
|
}
|
|
|
|
|
return null;
|
|
|
|
|
private MediaAttachmentViewController findPhotoViewHolder(int index){
|
|
|
|
|
return gridHolder.getViewController(index);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
@@ -310,31 +297,6 @@ public abstract class BaseStatusListFragment<T extends DisplayItemsParent> exten
|
|
|
|
|
updateToolbar();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
protected RecyclerView.LayoutManager onCreateLayoutManager(){
|
|
|
|
|
GridLayoutManager lm=new TileGridLayoutManager(getActivity(), 1000);
|
|
|
|
|
lm.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup(){
|
|
|
|
|
@Override
|
|
|
|
|
public int getSpanSize(int position){
|
|
|
|
|
position-=getMainAdapterOffset();
|
|
|
|
|
if(position>=0 && position<displayItems.size()){
|
|
|
|
|
StatusDisplayItem item=displayItems.get(position);
|
|
|
|
|
if(item instanceof ImageStatusDisplayItem imgItem){
|
|
|
|
|
PhotoLayoutHelper.TiledLayoutResult layout=imgItem.tiledLayout;
|
|
|
|
|
PhotoLayoutHelper.TiledLayoutResult.Tile tile=imgItem.thisTile;
|
|
|
|
|
int spans=0;
|
|
|
|
|
for(int i=0;i<tile.colSpan;i++){
|
|
|
|
|
spans+=layout.columnSizes[tile.startCol+i];
|
|
|
|
|
}
|
|
|
|
|
return spans;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return 1000;
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
return lm;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public void onConfigurationChanged(Configuration newConfig){
|
|
|
|
|
super.onConfigurationChanged(newConfig);
|
|
|
|
|
@@ -448,7 +410,7 @@ public abstract class BaseStatusListFragment<T extends DisplayItemsParent> exten
|
|
|
|
|
revealSpoiler(status, holder.getItemID());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void onRevealSpoilerClick(ImageStatusDisplayItem.Holder<?> holder){
|
|
|
|
|
public void onRevealSpoilerClick(MediaGridStatusDisplayItem.Holder holder){
|
|
|
|
|
Status status=holder.getItem().status;
|
|
|
|
|
revealSpoiler(status, holder.getItemID());
|
|
|
|
|
}
|
|
|
|
|
@@ -479,13 +441,14 @@ public abstract class BaseStatusListFragment<T extends DisplayItemsParent> exten
|
|
|
|
|
|
|
|
|
|
protected void updateImagesSpoilerState(Status status, String itemID){
|
|
|
|
|
ArrayList<Integer> updatedPositions=new ArrayList<>();
|
|
|
|
|
for(ImageStatusDisplayItem.Holder photo:(List<ImageStatusDisplayItem.Holder>)findAllHoldersOfType(itemID, ImageStatusDisplayItem.Holder.class)){
|
|
|
|
|
photo.setRevealed(status.spoilerRevealed);
|
|
|
|
|
updatedPositions.add(photo.getAbsoluteAdapterPosition()-getMainAdapterOffset());
|
|
|
|
|
MediaGridStatusDisplayItem.Holder mediaGrid=findHolderOfType(itemID, MediaGridStatusDisplayItem.Holder.class);
|
|
|
|
|
if(mediaGrid!=null){
|
|
|
|
|
mediaGrid.setRevealed(status.spoilerRevealed);
|
|
|
|
|
updatedPositions.add(mediaGrid.getAbsoluteAdapterPosition()-getMainAdapterOffset());
|
|
|
|
|
}
|
|
|
|
|
int i=0;
|
|
|
|
|
for(StatusDisplayItem item:displayItems){
|
|
|
|
|
if(itemID.equals(item.parentID) && item instanceof ImageStatusDisplayItem && !updatedPositions.contains(i)){
|
|
|
|
|
if(itemID.equals(item.parentID) && item instanceof MediaGridStatusDisplayItem && !updatedPositions.contains(i)){
|
|
|
|
|
adapter.notifyItemChanged(i);
|
|
|
|
|
}
|
|
|
|
|
i++;
|
|
|
|
|
@@ -609,6 +572,14 @@ public abstract class BaseStatusListFragment<T extends DisplayItemsParent> exten
|
|
|
|
|
currentPhotoViewer.onPause();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private MediaAttachmentViewController makeNewMediaAttachmentView(MediaGridStatusDisplayItem.GridItemType type){
|
|
|
|
|
return new MediaAttachmentViewController(getActivity(), type);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public TypedObjectPool<MediaGridStatusDisplayItem.GridItemType, MediaAttachmentViewController> getAttachmentViewsPool(){
|
|
|
|
|
return attachmentViewsPool;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected class DisplayItemsAdapter extends UsableRecyclerView.Adapter<BindableViewHolder<StatusDisplayItem>> implements ImageLoaderRecyclerAdapter{
|
|
|
|
|
|
|
|
|
|
public DisplayItemsAdapter(){
|
|
|
|
|
@@ -646,16 +617,6 @@ public abstract class BaseStatusListFragment<T extends DisplayItemsParent> exten
|
|
|
|
|
public ImageLoaderRequest getImageRequest(int position, int image){
|
|
|
|
|
return displayItems.get(position).getImageRequest(image);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// @Override
|
|
|
|
|
// public void onViewDetachedFromWindow(@NonNull BindableViewHolder<StatusDisplayItem> holder){
|
|
|
|
|
// if(holder instanceof ImageLoaderViewHolder){
|
|
|
|
|
// int count=holder.getItem().getImageCount();
|
|
|
|
|
// for(int i=0;i<count;i++){
|
|
|
|
|
// ((ImageLoaderViewHolder) holder).clearImage(i);
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private class StatusListItemDecoration extends RecyclerView.ItemDecoration{
|
|
|
|
|
@@ -689,25 +650,21 @@ public abstract class BaseStatusListFragment<T extends DisplayItemsParent> exten
|
|
|
|
|
for(int i=0;i<parent.getChildCount();i++){
|
|
|
|
|
View child=parent.getChildAt(i);
|
|
|
|
|
RecyclerView.ViewHolder holder=parent.getChildViewHolder(child);
|
|
|
|
|
if(holder instanceof ImageStatusDisplayItem.Holder<?> imgHolder){
|
|
|
|
|
if(holder instanceof MediaGridStatusDisplayItem.Holder imgHolder){
|
|
|
|
|
if(!imgHolder.getItem().status.spoilerRevealed && TextUtils.isEmpty(imgHolder.getItem().status.spoilerText)){
|
|
|
|
|
hiddenMediaPaint.setColor(0x80000000);
|
|
|
|
|
PhotoLayoutHelper.TiledLayoutResult.Tile tile=imgHolder.getItem().thisTile;
|
|
|
|
|
float hGap=tile.startCol>0 ? V.dp(1) : 0;
|
|
|
|
|
float vGap=tile.startRow>0 ? V.dp(1) : 0;
|
|
|
|
|
c.drawRect(child.getX()-hGap, child.getY()-vGap, child.getX()+child.getWidth(), child.getY()+child.getHeight(), hiddenMediaPaint);
|
|
|
|
|
c.drawRect(child.getX(), child.getY(), child.getX()+child.getWidth(), child.getY()+child.getHeight(), hiddenMediaPaint);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
for(int i=0;i<parent.getChildCount();i++){
|
|
|
|
|
View child=parent.getChildAt(i);
|
|
|
|
|
RecyclerView.ViewHolder holder=parent.getChildViewHolder(child);
|
|
|
|
|
if(holder instanceof ImageStatusDisplayItem.Holder<?> imgHolder){
|
|
|
|
|
if(holder instanceof MediaGridStatusDisplayItem.Holder imgHolder){
|
|
|
|
|
if(!imgHolder.getItem().status.spoilerRevealed){
|
|
|
|
|
PhotoLayoutHelper.TiledLayoutResult.Tile tile=imgHolder.getItem().thisTile;
|
|
|
|
|
if(tile.startCol==0 && tile.startRow==0 && TextUtils.isEmpty(imgHolder.getItem().status.spoilerText)){
|
|
|
|
|
if(TextUtils.isEmpty(imgHolder.getItem().status.spoilerText)){
|
|
|
|
|
int listWidth=getListWidthForMediaLayout();
|
|
|
|
|
int width=Math.min(listWidth, V.dp(ImageAttachmentFrameLayout.MAX_WIDTH));
|
|
|
|
|
int width=Math.min(listWidth, V.dp(MediaGridLayout.MAX_WIDTH));
|
|
|
|
|
if(currentMediaHiddenLayoutsWidth!=width)
|
|
|
|
|
rebuildMediaHiddenLayouts(width-V.dp(32));
|
|
|
|
|
c.save();
|
|
|
|
|
@@ -732,47 +689,6 @@ public abstract class BaseStatusListFragment<T extends DisplayItemsParent> exten
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull RecyclerView parent, @NonNull RecyclerView.State state){
|
|
|
|
|
RecyclerView.ViewHolder holder=parent.getChildViewHolder(view);
|
|
|
|
|
if(holder instanceof ImageStatusDisplayItem.Holder){
|
|
|
|
|
int listWidth=getListWidthForMediaLayout();
|
|
|
|
|
int width=Math.min(listWidth, V.dp(ImageAttachmentFrameLayout.MAX_WIDTH));
|
|
|
|
|
PhotoLayoutHelper.TiledLayoutResult layout=((ImageStatusDisplayItem.Holder<?>) holder).getItem().tiledLayout;
|
|
|
|
|
PhotoLayoutHelper.TiledLayoutResult.Tile tile=((ImageStatusDisplayItem.Holder<?>) holder).getItem().thisTile;
|
|
|
|
|
if(tile.startCol+tile.colSpan<layout.columnSizes.length){
|
|
|
|
|
outRect.right=V.dp(1);
|
|
|
|
|
}
|
|
|
|
|
if(tile.startRow+tile.rowSpan<layout.rowSizes.length){
|
|
|
|
|
outRect.bottom=V.dp(1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// For a view that spans rows, compensate its additional height so the row it's in stays the right height
|
|
|
|
|
if(tile.rowSpan>1){
|
|
|
|
|
outRect.bottom=-(Math.round(tile.height/1000f*width)-Math.round(layout.rowSizes[tile.startRow]/1000f*width));
|
|
|
|
|
}
|
|
|
|
|
// ...and for its siblings, offset those on rows below first to the right where they belong
|
|
|
|
|
if(tile.startCol>0 && layout.tiles[0].rowSpan>1 && tile.startRow>layout.tiles[0].startRow){
|
|
|
|
|
int xOffset=Math.round(layout.tiles[0].width/1000f*listWidth);
|
|
|
|
|
outRect.left=xOffset;
|
|
|
|
|
outRect.right=-xOffset;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// If the width of the media block is smaller than that of the RecyclerView, offset the views horizontally to center them
|
|
|
|
|
if(listWidth>width){
|
|
|
|
|
outRect.left+=(listWidth-V.dp(ImageAttachmentFrameLayout.MAX_WIDTH))/2;
|
|
|
|
|
if(tile.startCol>0){
|
|
|
|
|
int spanOffset=0;
|
|
|
|
|
for(int i=0;i<tile.startCol;i++){
|
|
|
|
|
spanOffset+=layout.columnSizes[i];
|
|
|
|
|
}
|
|
|
|
|
outRect.left-=Math.round(spanOffset/1000f*listWidth);
|
|
|
|
|
outRect.left+=Math.round(spanOffset/1000f*width);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void rebuildMediaHiddenLayouts(int width){
|
|
|
|
|
currentMediaHiddenLayoutsWidth=width;
|
|
|
|
|
String title=getString(R.string.sensitive_content);
|
|
|
|
|
|