Notifications
This commit is contained in:
parent
c3b7fb7002
commit
a4a514d37a
|
@ -0,0 +1,18 @@
|
|||
package org.joinmastodon.android.api.requests.notifications;
|
||||
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
|
||||
import org.joinmastodon.android.api.MastodonAPIRequest;
|
||||
import org.joinmastodon.android.model.Notification;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class GetNotifications extends MastodonAPIRequest<List<Notification>>{
|
||||
public GetNotifications(String maxID, int limit){
|
||||
super(HttpMethod.GET, "/notifications", new TypeToken<>(){});
|
||||
if(maxID!=null)
|
||||
addQueryParameter("max_id", maxID);
|
||||
if(limit>0)
|
||||
addQueryParameter("limit", ""+limit);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,251 @@
|
|||
package org.joinmastodon.android.fragments;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ImageView;
|
||||
|
||||
import org.joinmastodon.android.model.DisplayItemsParent;
|
||||
import org.joinmastodon.android.model.Status;
|
||||
import org.joinmastodon.android.ui.displayitems.PhotoStatusDisplayItem;
|
||||
import org.joinmastodon.android.ui.displayitems.StatusDisplayItem;
|
||||
import org.joinmastodon.android.ui.photoviewer.PhotoViewer;
|
||||
import org.joinmastodon.android.ui.photoviewer.PhotoViewerHost;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import me.grishka.appkit.fragments.BaseRecyclerFragment;
|
||||
import me.grishka.appkit.imageloader.ImageLoaderRecyclerAdapter;
|
||||
import me.grishka.appkit.imageloader.ImageLoaderViewHolder;
|
||||
import me.grishka.appkit.imageloader.requests.ImageLoaderRequest;
|
||||
import me.grishka.appkit.utils.BindableViewHolder;
|
||||
import me.grishka.appkit.views.UsableRecyclerView;
|
||||
|
||||
public abstract class BaseStatusListFragment<T extends DisplayItemsParent> extends BaseRecyclerFragment<T> implements PhotoViewerHost{
|
||||
protected ArrayList<StatusDisplayItem> displayItems=new ArrayList<>();
|
||||
protected DisplayItemsAdapter adapter;
|
||||
protected String accountID;
|
||||
protected PhotoViewer currentPhotoViewer;
|
||||
|
||||
public BaseStatusListFragment(){
|
||||
super(20);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected RecyclerView.Adapter getAdapter(){
|
||||
return adapter=new DisplayItemsAdapter();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAttach(Activity activity){
|
||||
super.onAttach(activity);
|
||||
accountID=getArguments().getString("account");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAppendItems(List<T> items){
|
||||
super.onAppendItems(items);
|
||||
for(T s:items){
|
||||
displayItems.addAll(buildDisplayItems(s));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClearItems(){
|
||||
super.onClearItems();
|
||||
displayItems.clear();
|
||||
}
|
||||
|
||||
protected void prependItems(List<T> items){
|
||||
data.addAll(0, items);
|
||||
int offset=0;
|
||||
for(T s:items){
|
||||
List<StatusDisplayItem> toAdd=buildDisplayItems(s);
|
||||
displayItems.addAll(offset, toAdd);
|
||||
offset+=toAdd.size();
|
||||
}
|
||||
adapter.notifyItemRangeInserted(0, offset);
|
||||
}
|
||||
|
||||
protected String getMaxID(){
|
||||
if(!preloadedData.isEmpty())
|
||||
return preloadedData.get(preloadedData.size()-1).getID();
|
||||
else if(!data.isEmpty())
|
||||
return data.get(data.size()-1).getID();
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
protected abstract List<StatusDisplayItem> buildDisplayItems(T s);
|
||||
|
||||
@Override
|
||||
protected void onHidden(){
|
||||
super.onHidden();
|
||||
// Clear any loaded images from the list to make it possible for the GC to deallocate them.
|
||||
// The delay avoids blank image views showing up in the app switcher.
|
||||
content.postDelayed(()->{
|
||||
if(!isHidden())
|
||||
return;
|
||||
imgLoader.deactivate();
|
||||
UsableRecyclerView list=(UsableRecyclerView) this.list;
|
||||
for(int i=0; i<list.getChildCount(); i++){
|
||||
RecyclerView.ViewHolder holder=list.getChildViewHolder(list.getChildAt(i));
|
||||
if(holder instanceof ImageLoaderViewHolder){
|
||||
for(int j=0; j<list.getImageCountForItem(holder.getAbsoluteAdapterPosition()); j++){
|
||||
((ImageLoaderViewHolder) holder).clearImage(j);
|
||||
}
|
||||
}
|
||||
}
|
||||
}, 100);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onShown(){
|
||||
super.onShown();
|
||||
imgLoader.activate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void openPhotoViewer(String parentID, Status _status, int attachmentIndex){
|
||||
final Status status=_status.reblog!=null ? _status.reblog : _status;
|
||||
currentPhotoViewer=new PhotoViewer(getActivity(), status.mediaAttachments, attachmentIndex, new PhotoViewer.Listener(){
|
||||
private PhotoStatusDisplayItem.Holder transitioningHolder;
|
||||
|
||||
@Override
|
||||
public void setPhotoViewVisibility(int index, boolean visible){
|
||||
PhotoStatusDisplayItem.Holder holder=findPhotoViewHolder(index);
|
||||
if(holder!=null)
|
||||
holder.photo.setAlpha(visible ? 1f : 0f);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean startPhotoViewTransition(int index, @NonNull Rect outRect, @NonNull int[] outCornerRadius){
|
||||
PhotoStatusDisplayItem.Holder holder=findPhotoViewHolder(index);
|
||||
if(holder!=null){
|
||||
transitioningHolder=holder;
|
||||
View view=transitioningHolder.photo;
|
||||
int[] pos={0, 0};
|
||||
view.getLocationOnScreen(pos);
|
||||
outRect.set(pos[0], pos[1], pos[0]+view.getWidth(), pos[1]+view.getHeight());
|
||||
list.setClipChildren(false);
|
||||
transitioningHolder.itemView.setElevation(1f);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTransitioningViewTransform(float translateX, float translateY, float scale){
|
||||
View view=transitioningHolder.photo;
|
||||
view.setTranslationX(translateX);
|
||||
view.setTranslationY(translateY);
|
||||
view.setScaleX(scale);
|
||||
view.setScaleY(scale);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endPhotoViewTransition(){
|
||||
View view=transitioningHolder.photo;
|
||||
view.setTranslationX(0f);
|
||||
view.setTranslationY(0f);
|
||||
view.setScaleX(1f);
|
||||
view.setScaleY(1f);
|
||||
transitioningHolder.itemView.setElevation(0f);
|
||||
list.setClipChildren(true);
|
||||
transitioningHolder=null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Drawable getPhotoViewCurrentDrawable(int index){
|
||||
PhotoStatusDisplayItem.Holder holder=findPhotoViewHolder(index);
|
||||
if(holder!=null)
|
||||
return holder.photo.getDrawable();
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void photoViewerDismissed(){
|
||||
currentPhotoViewer=null;
|
||||
}
|
||||
|
||||
private PhotoStatusDisplayItem.Holder findPhotoViewHolder(int index){
|
||||
int offset=0;
|
||||
for(StatusDisplayItem item:displayItems){
|
||||
if(item.parentID.equals(parentID)){
|
||||
if(item instanceof PhotoStatusDisplayItem){
|
||||
RecyclerView.ViewHolder holder=list.findViewHolderForAdapterPosition(getMainAdapterOffset()+offset+index);
|
||||
if(holder instanceof PhotoStatusDisplayItem.Holder){
|
||||
return (PhotoStatusDisplayItem.Holder) holder;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
offset++;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(View view, Bundle savedInstanceState){
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
list.addOnScrollListener(new RecyclerView.OnScrollListener(){
|
||||
@Override
|
||||
public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy){
|
||||
if(currentPhotoViewer!=null)
|
||||
currentPhotoViewer.offsetView(-dx, -dy);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected int getMainAdapterOffset(){
|
||||
return 0;
|
||||
}
|
||||
|
||||
protected class DisplayItemsAdapter extends UsableRecyclerView.Adapter<BindableViewHolder<StatusDisplayItem>> implements ImageLoaderRecyclerAdapter{
|
||||
|
||||
public DisplayItemsAdapter(){
|
||||
super(imgLoader);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public BindableViewHolder<StatusDisplayItem> onCreateViewHolder(@NonNull ViewGroup parent, int viewType){
|
||||
return (BindableViewHolder<StatusDisplayItem>) StatusDisplayItem.createViewHolder(StatusDisplayItem.Type.values()[viewType], getActivity(), parent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(BindableViewHolder<StatusDisplayItem> holder, int position){
|
||||
holder.bind(displayItems.get(position));
|
||||
super.onBindViewHolder(holder, position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount(){
|
||||
return displayItems.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemViewType(int position){
|
||||
return displayItems.get(position).getType().ordinal();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getImageCountForItem(int position){
|
||||
return displayItems.get(position).getImageCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImageLoaderRequest getImageRequest(int position, int image){
|
||||
return displayItems.get(position).getImageRequest(image);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -11,8 +11,10 @@ import com.squareup.otto.Subscribe;
|
|||
import org.joinmastodon.android.E;
|
||||
import org.joinmastodon.android.R;
|
||||
import org.joinmastodon.android.api.requests.timelines.GetHomeTimeline;
|
||||
import org.joinmastodon.android.api.session.AccountSessionManager;
|
||||
import org.joinmastodon.android.events.StatusCreatedEvent;
|
||||
import org.joinmastodon.android.model.Status;
|
||||
import org.parceler.Parcels;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
@ -32,14 +34,7 @@ public class HomeTimelineFragment extends StatusListFragment{
|
|||
|
||||
@Override
|
||||
protected void doLoadData(int offset, int count){
|
||||
String maxID;
|
||||
if(offset>0 && !preloadedData.isEmpty())
|
||||
maxID=preloadedData.get(preloadedData.size()-1).id;
|
||||
else if(offset>0 && !data.isEmpty())
|
||||
maxID=data.get(data.size()-1).id;
|
||||
else
|
||||
maxID=null;
|
||||
new GetHomeTimeline(maxID, null, count)
|
||||
new GetHomeTimeline(offset>0 ? getMaxID() : null, null, count)
|
||||
.setCallback(new SimpleCallback<>(this){
|
||||
@Override
|
||||
public void onSuccess(List<Status> result){
|
||||
|
@ -51,14 +46,22 @@ public class HomeTimelineFragment extends StatusListFragment{
|
|||
|
||||
@Override
|
||||
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater){
|
||||
menu.add("New toot");
|
||||
inflater.inflate(R.menu.home, menu);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item){
|
||||
Bundle args=new Bundle();
|
||||
args.putString("account", accountID);
|
||||
Nav.go(getActivity(), CreateTootFragment.class, args);
|
||||
int id=item.getItemId();
|
||||
if(id==R.id.new_toot){
|
||||
Nav.go(getActivity(), CreateTootFragment.class, args);
|
||||
}else if(id==R.id.notifications){
|
||||
Nav.go(getActivity(), NotificationsFragment.class, args);
|
||||
}else if(id==R.id.my_profile){
|
||||
args.putParcelable("profileAccount", Parcels.wrap(AccountSessionManager.getInstance().getAccount(accountID).self));
|
||||
Nav.go(getActivity(), ProfileFragment.class, args);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
package org.joinmastodon.android.fragments;
|
||||
|
||||
import android.app.Activity;
|
||||
|
||||
import org.joinmastodon.android.R;
|
||||
import org.joinmastodon.android.api.requests.notifications.GetNotifications;
|
||||
import org.joinmastodon.android.model.Notification;
|
||||
import org.joinmastodon.android.ui.displayitems.ReblogOrReplyLineStatusDisplayItem;
|
||||
import org.joinmastodon.android.ui.displayitems.StatusDisplayItem;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import me.grishka.appkit.api.SimpleCallback;
|
||||
|
||||
public class NotificationsFragment extends BaseStatusListFragment<Notification>{
|
||||
@Override
|
||||
public void onAttach(Activity activity){
|
||||
super.onAttach(activity);
|
||||
setTitle(R.string.notifications);
|
||||
loadData();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<StatusDisplayItem> buildDisplayItems(Notification n){
|
||||
ReblogOrReplyLineStatusDisplayItem titleItem=new ReblogOrReplyLineStatusDisplayItem(n.id, switch(n.type){
|
||||
case FOLLOW -> getString(R.string.user_followed_you, n.account.displayName);
|
||||
case FOLLOW_REQUEST -> getString(R.string.user_sent_follow_request, n.account.displayName);
|
||||
case MENTION -> getString(R.string.user_mentioned_you, n.account.displayName);
|
||||
case REBLOG -> getString(R.string.user_boosted, n.account.displayName);
|
||||
case FAVORITE -> getString(R.string.user_favorited, n.account.displayName);
|
||||
case POLL -> getString(R.string.poll_ended);
|
||||
case STATUS -> getString(R.string.user_posted, n.account.displayName);
|
||||
});
|
||||
if(n.status!=null){
|
||||
ArrayList<StatusDisplayItem> items=StatusDisplayItem.buildItems(this, n.status, accountID, n);
|
||||
items.add(0, titleItem);
|
||||
return items;
|
||||
}else{
|
||||
return Collections.singletonList(titleItem);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doLoadData(int offset, int count){
|
||||
new GetNotifications(offset>0 ? getMaxID() : null, count)
|
||||
.setCallback(new SimpleCallback<>(this){
|
||||
@Override
|
||||
public void onSuccess(List<Notification> result){
|
||||
onDataLoaded(result, !result.isEmpty());
|
||||
}
|
||||
})
|
||||
.exec(accountID);
|
||||
}
|
||||
}
|
|
@ -1,7 +1,6 @@
|
|||
package org.joinmastodon.android.fragments;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.os.Bundle;
|
||||
|
||||
import org.joinmastodon.android.api.requests.accounts.GetAccountStatuses;
|
||||
import org.joinmastodon.android.model.Account;
|
||||
|
@ -25,14 +24,7 @@ public class ProfileFragment extends StatusListFragment{
|
|||
|
||||
@Override
|
||||
protected void doLoadData(int offset, int count){
|
||||
String maxID;
|
||||
if(offset>0 && !preloadedData.isEmpty())
|
||||
maxID=preloadedData.get(preloadedData.size()-1).id;
|
||||
else if(offset>0 && !data.isEmpty())
|
||||
maxID=data.get(data.size()-1).id;
|
||||
else
|
||||
maxID=null;
|
||||
currentRequest=new GetAccountStatuses(user.id, maxID, null, count)
|
||||
currentRequest=new GetAccountStatuses(user.id, offset>0 ? getMaxID() : null, null, count)
|
||||
.setCallback(new SimpleCallback<>(this){
|
||||
@Override
|
||||
public void onSuccess(List<Status> result){
|
||||
|
|
|
@ -1,233 +1,12 @@
|
|||
package org.joinmastodon.android.fragments;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ImageView;
|
||||
|
||||
import org.joinmastodon.android.model.Status;
|
||||
import org.joinmastodon.android.ui.displayitems.PhotoStatusDisplayItem;
|
||||
import org.joinmastodon.android.ui.displayitems.StatusDisplayItem;
|
||||
import org.joinmastodon.android.ui.photoviewer.PhotoViewer;
|
||||
import org.joinmastodon.android.ui.photoviewer.PhotoViewerHost;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import me.grishka.appkit.fragments.BaseRecyclerFragment;
|
||||
import me.grishka.appkit.imageloader.ImageLoaderRecyclerAdapter;
|
||||
import me.grishka.appkit.imageloader.ImageLoaderViewHolder;
|
||||
import me.grishka.appkit.imageloader.requests.ImageLoaderRequest;
|
||||
import me.grishka.appkit.utils.BindableViewHolder;
|
||||
import me.grishka.appkit.views.UsableRecyclerView;
|
||||
|
||||
public abstract class StatusListFragment extends BaseRecyclerFragment<Status> implements PhotoViewerHost{
|
||||
protected ArrayList<StatusDisplayItem> displayItems=new ArrayList<>();
|
||||
protected DisplayItemsAdapter adapter;
|
||||
protected String accountID;
|
||||
protected PhotoViewer currentPhotoViewer;
|
||||
|
||||
public StatusListFragment(){
|
||||
super(20);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected RecyclerView.Adapter getAdapter(){
|
||||
return adapter=new DisplayItemsAdapter();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAttach(Activity activity){
|
||||
super.onAttach(activity);
|
||||
accountID=getArguments().getString("account");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAppendItems(List<Status> items){
|
||||
super.onAppendItems(items);
|
||||
for(Status s:items){
|
||||
displayItems.addAll(StatusDisplayItem.buildItems(this, s, accountID));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClearItems(){
|
||||
super.onClearItems();
|
||||
displayItems.clear();
|
||||
}
|
||||
|
||||
protected void prependItems(List<Status> items){
|
||||
data.addAll(0, items);
|
||||
int offset=0;
|
||||
for(Status s:items){
|
||||
List<StatusDisplayItem> toAdd=StatusDisplayItem.buildItems(this, s, accountID);
|
||||
displayItems.addAll(offset, toAdd);
|
||||
offset+=toAdd.size();
|
||||
}
|
||||
adapter.notifyItemRangeInserted(0, offset);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onHidden(){
|
||||
super.onHidden();
|
||||
imgLoader.deactivate();
|
||||
UsableRecyclerView list=(UsableRecyclerView) this.list;
|
||||
for(int i=0;i<list.getChildCount();i++){
|
||||
RecyclerView.ViewHolder holder=list.getChildViewHolder(list.getChildAt(i));
|
||||
if(holder instanceof ImageLoaderViewHolder){
|
||||
for(int j=0;j<list.getImageCountForItem(holder.getAbsoluteAdapterPosition());j++){
|
||||
((ImageLoaderViewHolder) holder).clearImage(j);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onShown(){
|
||||
super.onShown();
|
||||
imgLoader.activate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void openPhotoViewer(Status _status, int attachmentIndex){
|
||||
final Status status=_status.reblog!=null ? _status.reblog : _status;
|
||||
currentPhotoViewer=new PhotoViewer(getActivity(), status.mediaAttachments, attachmentIndex, new PhotoViewer.Listener(){
|
||||
private PhotoStatusDisplayItem.Holder transitioningHolder;
|
||||
|
||||
@Override
|
||||
public void setPhotoViewVisibility(int index, boolean visible){
|
||||
PhotoStatusDisplayItem.Holder holder=findPhotoViewHolder(index);
|
||||
if(holder!=null)
|
||||
holder.photo.setAlpha(visible ? 1f : 0f);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean startPhotoViewTransition(int index, @NonNull Rect outRect, @NonNull int[] outCornerRadius){
|
||||
PhotoStatusDisplayItem.Holder holder=findPhotoViewHolder(index);
|
||||
if(holder!=null){
|
||||
transitioningHolder=holder;
|
||||
View view=transitioningHolder.photo;
|
||||
int[] pos={0, 0};
|
||||
view.getLocationOnScreen(pos);
|
||||
outRect.set(pos[0], pos[1], pos[0]+view.getWidth(), pos[1]+view.getHeight());
|
||||
list.setClipChildren(false);
|
||||
transitioningHolder.itemView.setElevation(1f);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTransitioningViewTransform(float translateX, float translateY, float scale){
|
||||
View view=transitioningHolder.photo;
|
||||
view.setTranslationX(translateX);
|
||||
view.setTranslationY(translateY);
|
||||
view.setScaleX(scale);
|
||||
view.setScaleY(scale);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endPhotoViewTransition(){
|
||||
View view=transitioningHolder.photo;
|
||||
view.setTranslationX(0f);
|
||||
view.setTranslationY(0f);
|
||||
view.setScaleX(1f);
|
||||
view.setScaleY(1f);
|
||||
transitioningHolder.itemView.setElevation(0f);
|
||||
list.setClipChildren(true);
|
||||
transitioningHolder=null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Drawable getPhotoViewCurrentDrawable(int index){
|
||||
PhotoStatusDisplayItem.Holder holder=findPhotoViewHolder(index);
|
||||
if(holder!=null)
|
||||
return holder.photo.getDrawable();
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void photoViewerDismissed(){
|
||||
currentPhotoViewer=null;
|
||||
}
|
||||
|
||||
private PhotoStatusDisplayItem.Holder findPhotoViewHolder(int index){
|
||||
int offset=0;
|
||||
for(StatusDisplayItem item:displayItems){
|
||||
if(item.status==_status){
|
||||
if(item instanceof PhotoStatusDisplayItem){
|
||||
RecyclerView.ViewHolder holder=list.findViewHolderForAdapterPosition(getMainAdapterOffset()+offset+index);
|
||||
if(holder instanceof PhotoStatusDisplayItem.Holder){
|
||||
return (PhotoStatusDisplayItem.Holder) holder;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
offset++;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(View view, Bundle savedInstanceState){
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
list.addOnScrollListener(new RecyclerView.OnScrollListener(){
|
||||
@Override
|
||||
public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy){
|
||||
if(currentPhotoViewer!=null)
|
||||
currentPhotoViewer.offsetView(-dx, -dy);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected int getMainAdapterOffset(){
|
||||
return 0;
|
||||
}
|
||||
|
||||
protected class DisplayItemsAdapter extends UsableRecyclerView.Adapter<BindableViewHolder<StatusDisplayItem>> implements ImageLoaderRecyclerAdapter{
|
||||
|
||||
public DisplayItemsAdapter(){
|
||||
super(imgLoader);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public BindableViewHolder<StatusDisplayItem> onCreateViewHolder(@NonNull ViewGroup parent, int viewType){
|
||||
return (BindableViewHolder<StatusDisplayItem>) StatusDisplayItem.createViewHolder(StatusDisplayItem.Type.values()[viewType], getActivity(), parent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(BindableViewHolder<StatusDisplayItem> holder, int position){
|
||||
holder.bind(displayItems.get(position));
|
||||
super.onBindViewHolder(holder, position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount(){
|
||||
return displayItems.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemViewType(int position){
|
||||
return displayItems.get(position).getType().ordinal();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getImageCountForItem(int position){
|
||||
return displayItems.get(position).getImageCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImageLoaderRequest getImageRequest(int position, int image){
|
||||
return displayItems.get(position).getImageRequest(image);
|
||||
}
|
||||
public abstract class StatusListFragment extends BaseStatusListFragment<Status>{
|
||||
protected List<StatusDisplayItem> buildDisplayItems(Status s){
|
||||
return StatusDisplayItem.buildItems(this, s, accountID, s);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
package org.joinmastodon.android.model;
|
||||
|
||||
/**
|
||||
* A model object from which {@link org.joinmastodon.android.ui.displayitems.StatusDisplayItem}s can be generated.
|
||||
*/
|
||||
public interface DisplayItemsParent{
|
||||
String getID();
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
package org.joinmastodon.android.model;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
import org.joinmastodon.android.api.ObjectValidationException;
|
||||
import org.joinmastodon.android.api.RequiredField;
|
||||
|
||||
import java.time.Instant;
|
||||
|
||||
public class Notification extends BaseModel implements DisplayItemsParent{
|
||||
@RequiredField
|
||||
public String id;
|
||||
@RequiredField
|
||||
public Type type;
|
||||
@RequiredField
|
||||
public Instant createdAt;
|
||||
@RequiredField
|
||||
public Account account;
|
||||
|
||||
public Status status;
|
||||
|
||||
@Override
|
||||
public void postprocess() throws ObjectValidationException{
|
||||
super.postprocess();
|
||||
account.postprocess();
|
||||
if(status!=null)
|
||||
status.postprocess();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getID(){
|
||||
return id;
|
||||
}
|
||||
|
||||
public enum Type{
|
||||
@SerializedName("follow")
|
||||
FOLLOW,
|
||||
@SerializedName("follow_request")
|
||||
FOLLOW_REQUEST,
|
||||
@SerializedName("mention")
|
||||
MENTION,
|
||||
@SerializedName("reblog")
|
||||
REBLOG,
|
||||
@SerializedName("favourite")
|
||||
FAVORITE,
|
||||
@SerializedName("poll")
|
||||
POLL,
|
||||
@SerializedName("status")
|
||||
STATUS
|
||||
}
|
||||
}
|
|
@ -1,17 +1,12 @@
|
|||
package org.joinmastodon.android.model;
|
||||
|
||||
import android.text.Html;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
|
||||
import org.joinmastodon.android.api.ObjectValidationException;
|
||||
import org.joinmastodon.android.api.RequiredField;
|
||||
import org.joinmastodon.android.ui.text.HtmlParser;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.List;
|
||||
|
||||
public class Status extends BaseModel{
|
||||
public class Status extends BaseModel implements DisplayItemsParent{
|
||||
@RequiredField
|
||||
public String id;
|
||||
@RequiredField
|
||||
|
@ -111,4 +106,9 @@ public class Status extends BaseModel{
|
|||
", pinned="+pinned+
|
||||
'}';
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getID(){
|
||||
return id;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,8 +31,8 @@ public class HeaderStatusDisplayItem extends StatusDisplayItem{
|
|||
private Fragment parentFragment;
|
||||
private String accountID;
|
||||
|
||||
public HeaderStatusDisplayItem(Status status, Account user, Instant createdAt, Fragment parentFragment, String accountID){
|
||||
super(status);
|
||||
public HeaderStatusDisplayItem(String parentID, Account user, Instant createdAt, Fragment parentFragment, String accountID){
|
||||
super(parentID);
|
||||
this.user=user;
|
||||
this.createdAt=createdAt;
|
||||
avaRequest=new UrlImageLoaderRequest(user.avatar);
|
||||
|
|
|
@ -21,8 +21,10 @@ public class PhotoStatusDisplayItem extends StatusDisplayItem{
|
|||
private Attachment attachment;
|
||||
private ImageLoaderRequest request;
|
||||
private Fragment parentFragment;
|
||||
public PhotoStatusDisplayItem(Status status, Attachment photo, Fragment parentFragment){
|
||||
super(status);
|
||||
private Status status;
|
||||
public PhotoStatusDisplayItem(String parentID, Status status, Attachment photo, Fragment parentFragment){
|
||||
super(parentID);
|
||||
this.status=status;
|
||||
this.attachment=photo;
|
||||
request=new UrlImageLoaderRequest(photo.url, 1000, 1000);
|
||||
this.parentFragment=parentFragment;
|
||||
|
@ -69,7 +71,7 @@ public class PhotoStatusDisplayItem extends StatusDisplayItem{
|
|||
private void onViewClick(View v){
|
||||
if(item.parentFragment instanceof PhotoViewerHost){
|
||||
Status contentStatus=item.status.reblog!=null ? item.status.reblog : item.status;
|
||||
((PhotoViewerHost) item.parentFragment).openPhotoViewer(item.status, contentStatus.mediaAttachments.indexOf(item.attachment));
|
||||
((PhotoViewerHost) item.parentFragment).openPhotoViewer(item.parentID, item.status, contentStatus.mediaAttachments.indexOf(item.attachment));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,8 +10,11 @@ import org.joinmastodon.android.model.Status;
|
|||
import me.grishka.appkit.utils.BindableViewHolder;
|
||||
|
||||
public class ReblogOrReplyLineStatusDisplayItem extends StatusDisplayItem{
|
||||
public ReblogOrReplyLineStatusDisplayItem(Status status){
|
||||
super(status);
|
||||
private CharSequence text;
|
||||
|
||||
public ReblogOrReplyLineStatusDisplayItem(String parentID, CharSequence text){
|
||||
super(parentID);
|
||||
this.text=text;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -28,9 +31,7 @@ public class ReblogOrReplyLineStatusDisplayItem extends StatusDisplayItem{
|
|||
|
||||
@Override
|
||||
public void onBind(ReblogOrReplyLineStatusDisplayItem item){
|
||||
if(item.status.reblog!=null){
|
||||
text.setText(itemView.getContext().getString(R.string.user_boosted, item.status.account.displayName));
|
||||
}
|
||||
text.setText(item.text);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,21 +5,22 @@ import android.app.Fragment;
|
|||
import android.text.TextUtils;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import org.joinmastodon.android.R;
|
||||
import org.joinmastodon.android.model.Attachment;
|
||||
import org.joinmastodon.android.model.DisplayItemsParent;
|
||||
import org.joinmastodon.android.model.Status;
|
||||
import org.joinmastodon.android.ui.text.HtmlParser;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import me.grishka.appkit.imageloader.requests.ImageLoaderRequest;
|
||||
import me.grishka.appkit.utils.BindableViewHolder;
|
||||
|
||||
public abstract class StatusDisplayItem{
|
||||
public final Status status;
|
||||
public final String parentID;
|
||||
|
||||
public StatusDisplayItem(Status status){
|
||||
this.status=status;
|
||||
public StatusDisplayItem(String parentID){
|
||||
this.parentID=parentID;
|
||||
}
|
||||
|
||||
public abstract Type getType();
|
||||
|
@ -42,18 +43,19 @@ public abstract class StatusDisplayItem{
|
|||
};
|
||||
}
|
||||
|
||||
public static List<StatusDisplayItem> buildItems(Fragment fragment, Status status, String accountID){
|
||||
public static ArrayList<StatusDisplayItem> buildItems(Fragment fragment, Status status, String accountID, DisplayItemsParent parentObject){
|
||||
String parentID=parentObject.getID();
|
||||
ArrayList<StatusDisplayItem> items=new ArrayList<>();
|
||||
Status statusForContent=status.reblog==null ? status : status.reblog;
|
||||
if(status.reblog!=null){
|
||||
items.add(new ReblogOrReplyLineStatusDisplayItem(status));
|
||||
items.add(new ReblogOrReplyLineStatusDisplayItem(parentID, fragment.getString(R.string.user_boosted, status.account.displayName)));
|
||||
}
|
||||
items.add(new HeaderStatusDisplayItem(status, statusForContent.account, statusForContent.createdAt, fragment, accountID));
|
||||
items.add(new HeaderStatusDisplayItem(parentID, statusForContent.account, statusForContent.createdAt, fragment, accountID));
|
||||
if(!TextUtils.isEmpty(statusForContent.content))
|
||||
items.add(new TextStatusDisplayItem(status, HtmlParser.parse(statusForContent.content, statusForContent.emojis), fragment));
|
||||
items.add(new TextStatusDisplayItem(parentID, HtmlParser.parse(statusForContent.content, statusForContent.emojis), fragment));
|
||||
for(Attachment attachment:statusForContent.mediaAttachments){
|
||||
if(attachment.type==Attachment.Type.IMAGE){
|
||||
items.add(new PhotoStatusDisplayItem(status, attachment, fragment));
|
||||
items.add(new PhotoStatusDisplayItem(parentID, status, attachment, fragment));
|
||||
}
|
||||
}
|
||||
return items;
|
||||
|
|
|
@ -26,8 +26,8 @@ public class TextStatusDisplayItem extends StatusDisplayItem implements LinkSpan
|
|||
private CharSequence text;
|
||||
private ImageLoaderRequest[] emojiRequests;
|
||||
private Fragment parentFragment;
|
||||
public TextStatusDisplayItem(Status status, CharSequence text, Fragment parentFragment){
|
||||
super(status);
|
||||
public TextStatusDisplayItem(String parentID, CharSequence text, Fragment parentFragment){
|
||||
super(parentID);
|
||||
this.text=text;
|
||||
this.parentFragment=parentFragment;
|
||||
if(text instanceof Spanned){
|
||||
|
|
|
@ -3,5 +3,5 @@ package org.joinmastodon.android.ui.photoviewer;
|
|||
import org.joinmastodon.android.model.Status;
|
||||
|
||||
public interface PhotoViewerHost{
|
||||
void openPhotoViewer(Status status, int attachmentIndex);
|
||||
void openPhotoViewer(String parentID, Status status, int attachmentIndex);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:id="@+id/new_toot" android:title="New toot"/>
|
||||
<item android:id="@+id/notifications" android:title="@string/notifications"/>
|
||||
<item android:id="@+id/my_profile" android:title="My profile"/>
|
||||
</menu>
|
|
@ -12,4 +12,12 @@
|
|||
<string name="finishing_auth">Finishing authentication…</string>
|
||||
<string name="user_boosted">%s boosted</string>
|
||||
<string name="replied_to">Replied to %s</string>
|
||||
<string name="notifications">Notifications</string>
|
||||
|
||||
<string name="user_followed_you">%s followed you</string>
|
||||
<string name="user_sent_follow_request">%s sent you a follow request</string>
|
||||
<string name="user_mentioned_you">%s mentioned you</string>
|
||||
<string name="user_favorited">%s favorited your toot</string>
|
||||
<string name="poll_ended">Poll you voted in has ended</string>
|
||||
<string name="user_posted">%s posted</string>
|
||||
</resources>
|
Loading…
Reference in New Issue