Make status placeholder abstraction cleaner
This commit is contained in:
parent
0dede1ba7d
commit
74d6736afc
|
@ -113,7 +113,7 @@ public class NotificationsAdapter extends RecyclerView.Adapter {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case MENTION: {
|
case MENTION: {
|
||||||
StatusViewHolder holder = (StatusViewHolder) viewHolder;
|
StatusViewHolder holder = (StatusViewHolder) viewHolder;
|
||||||
StatusViewData status = concreteNotificaton.getStatusViewData();
|
StatusViewData.Concrete status = concreteNotificaton.getStatusViewData();
|
||||||
holder.setupWithStatus(status,
|
holder.setupWithStatus(status,
|
||||||
statusListener, mediaPreviewEnabled);
|
statusListener, mediaPreviewEnabled);
|
||||||
break;
|
break;
|
||||||
|
@ -279,7 +279,8 @@ public class NotificationsAdapter extends RecyclerView.Adapter {
|
||||||
notificationAvatar.setColorFilter(darkerFilter, PorterDuff.Mode.MULTIPLY);
|
notificationAvatar.setColorFilter(darkerFilter, PorterDuff.Mode.MULTIPLY);
|
||||||
}
|
}
|
||||||
|
|
||||||
void setMessage(Notification.Type type, String displayName, StatusViewData status) {
|
void setMessage(Notification.Type type, String displayName,
|
||||||
|
StatusViewData.Concrete status) {
|
||||||
Context context = message.getContext();
|
Context context = message.getContext();
|
||||||
String format;
|
String format;
|
||||||
switch (type) {
|
switch (type) {
|
||||||
|
|
|
@ -473,7 +473,7 @@ class StatusBaseViewHolder extends RecyclerView.ViewHolder {
|
||||||
container.setOnClickListener(viewThreadListener);
|
container.setOnClickListener(viewThreadListener);
|
||||||
}
|
}
|
||||||
|
|
||||||
void setupWithStatus(StatusViewData status, final StatusActionListener listener,
|
void setupWithStatus(StatusViewData.Concrete status, final StatusActionListener listener,
|
||||||
boolean mediaPreviewEnabled) {
|
boolean mediaPreviewEnabled) {
|
||||||
setDisplayName(status.getUserFullName());
|
setDisplayName(status.getUserFullName());
|
||||||
setUsername(status.getNickname());
|
setUsername(status.getNickname());
|
||||||
|
|
|
@ -85,7 +85,7 @@ class StatusDetailedViewHolder extends StatusBaseViewHolder {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
void setupWithStatus(final StatusViewData status, final StatusActionListener listener,
|
void setupWithStatus(final StatusViewData.Concrete status, final StatusActionListener listener,
|
||||||
boolean mediaPreviewEnabled) {
|
boolean mediaPreviewEnabled) {
|
||||||
super.setupWithStatus(status, listener, mediaPreviewEnabled);
|
super.setupWithStatus(status, listener, mediaPreviewEnabled);
|
||||||
reblogs.setText(status.getReblogsCount());
|
reblogs.setText(status.getReblogsCount());
|
||||||
|
|
|
@ -67,7 +67,7 @@ public class StatusViewHolder extends StatusBaseViewHolder {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
void setupWithStatus(StatusViewData status, final StatusActionListener listener,
|
void setupWithStatus(StatusViewData.Concrete status, final StatusActionListener listener,
|
||||||
boolean mediaPreviewEnabled) {
|
boolean mediaPreviewEnabled) {
|
||||||
super.setupWithStatus(status, listener, mediaPreviewEnabled);
|
super.setupWithStatus(status, listener, mediaPreviewEnabled);
|
||||||
|
|
||||||
|
|
|
@ -33,7 +33,7 @@ public class ThreadAdapter extends RecyclerView.Adapter {
|
||||||
private static final int VIEW_TYPE_STATUS = 0;
|
private static final int VIEW_TYPE_STATUS = 0;
|
||||||
private static final int VIEW_TYPE_STATUS_DETAILED = 1;
|
private static final int VIEW_TYPE_STATUS_DETAILED = 1;
|
||||||
|
|
||||||
private List<StatusViewData> statuses;
|
private List<StatusViewData.Concrete> statuses;
|
||||||
private StatusActionListener statusActionListener;
|
private StatusActionListener statusActionListener;
|
||||||
private boolean mediaPreviewEnabled;
|
private boolean mediaPreviewEnabled;
|
||||||
private int detailedStatusPosition;
|
private int detailedStatusPosition;
|
||||||
|
@ -66,13 +66,12 @@ public class ThreadAdapter extends RecyclerView.Adapter {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int position) {
|
public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int position) {
|
||||||
|
StatusViewData.Concrete status = statuses.get(position);
|
||||||
if (position == detailedStatusPosition) {
|
if (position == detailedStatusPosition) {
|
||||||
StatusDetailedViewHolder holder = (StatusDetailedViewHolder) viewHolder;
|
StatusDetailedViewHolder holder = (StatusDetailedViewHolder) viewHolder;
|
||||||
StatusViewData status = statuses.get(position);
|
|
||||||
holder.setupWithStatus(status, statusActionListener, mediaPreviewEnabled);
|
holder.setupWithStatus(status, statusActionListener, mediaPreviewEnabled);
|
||||||
} else {
|
} else {
|
||||||
StatusViewHolder holder = (StatusViewHolder) viewHolder;
|
StatusViewHolder holder = (StatusViewHolder) viewHolder;
|
||||||
StatusViewData status = statuses.get(position);
|
|
||||||
holder.setupWithStatus(status, statusActionListener, mediaPreviewEnabled);
|
holder.setupWithStatus(status, statusActionListener, mediaPreviewEnabled);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -91,13 +90,13 @@ public class ThreadAdapter extends RecyclerView.Adapter {
|
||||||
return statuses.size();
|
return statuses.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setStatuses(List<StatusViewData> statuses) {
|
public void setStatuses(List<StatusViewData.Concrete> statuses) {
|
||||||
this.statuses.clear();
|
this.statuses.clear();
|
||||||
this.statuses.addAll(statuses);
|
this.statuses.addAll(statuses);
|
||||||
notifyDataSetChanged();
|
notifyDataSetChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addItem(int position, StatusViewData statusViewData) {
|
public void addItem(int position, StatusViewData.Concrete statusViewData) {
|
||||||
statuses.add(position, statusViewData);
|
statuses.add(position, statusViewData);
|
||||||
notifyItemInserted(position);
|
notifyItemInserted(position);
|
||||||
}
|
}
|
||||||
|
@ -109,12 +108,12 @@ public class ThreadAdapter extends RecyclerView.Adapter {
|
||||||
notifyItemRangeRemoved(0, oldSize);
|
notifyItemRangeRemoved(0, oldSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addAll(int position, List<StatusViewData> statuses) {
|
public void addAll(int position, List<StatusViewData.Concrete> statuses) {
|
||||||
this.statuses.addAll(position, statuses);
|
this.statuses.addAll(position, statuses);
|
||||||
notifyItemRangeInserted(position, statuses.size());
|
notifyItemRangeInserted(position, statuses.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addAll(List<StatusViewData> statuses) {
|
public void addAll(List<StatusViewData.Concrete> statuses) {
|
||||||
int end = statuses.size();
|
int end = statuses.size();
|
||||||
this.statuses.addAll(statuses);
|
this.statuses.addAll(statuses);
|
||||||
notifyItemRangeInserted(end, statuses.size());
|
notifyItemRangeInserted(end, statuses.size());
|
||||||
|
@ -126,7 +125,7 @@ public class ThreadAdapter extends RecyclerView.Adapter {
|
||||||
notifyDataSetChanged();
|
notifyDataSetChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setItem(int position, StatusViewData status, boolean notifyAdapter) {
|
public void setItem(int position, StatusViewData.Concrete status, boolean notifyAdapter) {
|
||||||
statuses.set(position, status);
|
statuses.set(position, status);
|
||||||
if (notifyAdapter) {
|
if (notifyAdapter) {
|
||||||
notifyItemChanged(position);
|
notifyItemChanged(position);
|
||||||
|
@ -134,7 +133,7 @@ public class ThreadAdapter extends RecyclerView.Adapter {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
public StatusViewData getItem(int position) {
|
public StatusViewData.Concrete getItem(int position) {
|
||||||
if (position != RecyclerView.NO_POSITION && position >= 0 && position < statuses.size()) {
|
if (position != RecyclerView.NO_POSITION && position >= 0 && position < statuses.size()) {
|
||||||
return statuses.get(position);
|
return statuses.get(position);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -72,12 +72,14 @@ public class TimelineAdapter extends RecyclerView.Adapter {
|
||||||
public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int position) {
|
public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int position) {
|
||||||
if (position < statuses.size()) {
|
if (position < statuses.size()) {
|
||||||
StatusViewData status = statuses.get(position);
|
StatusViewData status = statuses.get(position);
|
||||||
if(status.isPlaceholder()) {
|
if (status instanceof StatusViewData.Placeholder) {
|
||||||
PlaceholderViewHolder holder = (PlaceholderViewHolder) viewHolder;
|
PlaceholderViewHolder holder = (PlaceholderViewHolder) viewHolder;
|
||||||
holder.setup(!status.isPlaceholderLoading(), statusListener);
|
holder.setup(!((StatusViewData.Placeholder) status).isLoading(), statusListener);
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
StatusViewHolder holder = (StatusViewHolder) viewHolder;
|
StatusViewHolder holder = (StatusViewHolder) viewHolder;
|
||||||
holder.setupWithStatus(status, statusListener, mediaPreviewEnabled);
|
holder.setupWithStatus((StatusViewData.Concrete) status,
|
||||||
|
statusListener, mediaPreviewEnabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
@ -96,7 +98,7 @@ public class TimelineAdapter extends RecyclerView.Adapter {
|
||||||
if (position == statuses.size()) {
|
if (position == statuses.size()) {
|
||||||
return VIEW_TYPE_FOOTER;
|
return VIEW_TYPE_FOOTER;
|
||||||
} else {
|
} else {
|
||||||
if(statuses.get(position).isPlaceholder()) {
|
if (statuses.get(position) instanceof StatusViewData.Placeholder) {
|
||||||
return VIEW_TYPE_PLACEHOLDER;
|
return VIEW_TYPE_PLACEHOLDER;
|
||||||
} else {
|
} else {
|
||||||
return VIEW_TYPE_STATUS;
|
return VIEW_TYPE_STATUS;
|
||||||
|
|
|
@ -27,10 +27,6 @@ import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class Status {
|
public class Status {
|
||||||
/*if placeholder == true, this is not a real status, but a placeholder "load more"
|
|
||||||
and the id represents the max_id for the request*/
|
|
||||||
public boolean placeholder;
|
|
||||||
|
|
||||||
public String url;
|
public String url;
|
||||||
|
|
||||||
@SerializedName("reblogs_count")
|
@SerializedName("reblogs_count")
|
||||||
|
@ -115,16 +111,12 @@ public class Status {
|
||||||
if (o == null || getClass() != o.getClass()) return false;
|
if (o == null || getClass() != o.getClass()) return false;
|
||||||
|
|
||||||
Status status = (Status) o;
|
Status status = (Status) o;
|
||||||
|
|
||||||
if (placeholder != status.placeholder) return false;
|
|
||||||
return id != null ? id.equals(status.id) : status.id == null;
|
return id != null ? id.equals(status.id) : status.id == null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
int result = (placeholder ? 1 : 0);
|
return id != null ? id.hashCode() : 0;
|
||||||
result = 31 * result + (id != null ? id.hashCode() : 0);
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class MediaAttachment {
|
public static class MediaAttachment {
|
||||||
|
|
|
@ -340,7 +340,7 @@ public class NotificationsFragment extends SFragment implements
|
||||||
public void onExpandedChange(boolean expanded, int position) {
|
public void onExpandedChange(boolean expanded, int position) {
|
||||||
NotificationViewData.Concrete old =
|
NotificationViewData.Concrete old =
|
||||||
(NotificationViewData.Concrete) notifications.getPairedItem(position);
|
(NotificationViewData.Concrete) notifications.getPairedItem(position);
|
||||||
StatusViewData statusViewData =
|
StatusViewData.Concrete statusViewData =
|
||||||
new StatusViewData.Builder(old.getStatusViewData())
|
new StatusViewData.Builder(old.getStatusViewData())
|
||||||
.setIsExpanded(expanded)
|
.setIsExpanded(expanded)
|
||||||
.createStatusViewData();
|
.createStatusViewData();
|
||||||
|
@ -354,7 +354,7 @@ public class NotificationsFragment extends SFragment implements
|
||||||
public void onContentHiddenChange(boolean isShowing, int position) {
|
public void onContentHiddenChange(boolean isShowing, int position) {
|
||||||
NotificationViewData.Concrete old =
|
NotificationViewData.Concrete old =
|
||||||
(NotificationViewData.Concrete) notifications.getPairedItem(position);
|
(NotificationViewData.Concrete) notifications.getPairedItem(position);
|
||||||
StatusViewData statusViewData =
|
StatusViewData.Concrete statusViewData =
|
||||||
new StatusViewData.Builder(old.getStatusViewData())
|
new StatusViewData.Builder(old.getStatusViewData())
|
||||||
.setIsShowingSensitiveContent(isShowing)
|
.setIsShowingSensitiveContent(isShowing)
|
||||||
.createStatusViewData();
|
.createStatusViewData();
|
||||||
|
@ -368,10 +368,13 @@ public class NotificationsFragment extends SFragment implements
|
||||||
public void onLoadMore(int position) {
|
public void onLoadMore(int position) {
|
||||||
//check bounds before accessing list,
|
//check bounds before accessing list,
|
||||||
if (notifications.size() >= position && position > 0) {
|
if (notifications.size() >= position && position > 0) {
|
||||||
// is it safe?
|
Notification previous = notifications.get(position - 1).getAsRightOrNull();
|
||||||
String fromId = notifications.get(position - 1).getAsRight().id;
|
Notification next = notifications.get(position + 1).getAsRightOrNull();
|
||||||
String toId = notifications.get(position + 1).getAsRight().id;
|
if (previous == null || next == null) {
|
||||||
sendFetchNotificationsRequest(fromId, toId, FetchEnd.MIDDLE, position);
|
Log.e(TAG, "Failed to load more, invalid placeholder position: " + position);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
sendFetchNotificationsRequest(previous.id, next.id, FetchEnd.MIDDLE, position);
|
||||||
NotificationViewData notificationViewData =
|
NotificationViewData notificationViewData =
|
||||||
new NotificationViewData.Placeholder(true);
|
new NotificationViewData.Placeholder(true);
|
||||||
notifications.setPairedItem(position, notificationViewData);
|
notifications.setPairedItem(position, notificationViewData);
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
|
|
||||||
package com.keylesspalace.tusky.fragment;
|
package com.keylesspalace.tusky.fragment;
|
||||||
|
|
||||||
|
import android.arch.core.util.Function;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.drawable.Drawable;
|
||||||
|
@ -25,6 +26,7 @@ import android.support.annotation.Nullable;
|
||||||
import android.support.design.widget.FloatingActionButton;
|
import android.support.design.widget.FloatingActionButton;
|
||||||
import android.support.design.widget.TabLayout;
|
import android.support.design.widget.TabLayout;
|
||||||
import android.support.v4.content.LocalBroadcastManager;
|
import android.support.v4.content.LocalBroadcastManager;
|
||||||
|
import android.support.v4.util.Pair;
|
||||||
import android.support.v4.widget.SwipeRefreshLayout;
|
import android.support.v4.widget.SwipeRefreshLayout;
|
||||||
import android.support.v7.widget.DividerItemDecoration;
|
import android.support.v7.widget.DividerItemDecoration;
|
||||||
import android.support.v7.widget.LinearLayoutManager;
|
import android.support.v7.widget.LinearLayoutManager;
|
||||||
|
@ -43,6 +45,8 @@ import com.keylesspalace.tusky.interfaces.ActionButtonActivity;
|
||||||
import com.keylesspalace.tusky.interfaces.StatusActionListener;
|
import com.keylesspalace.tusky.interfaces.StatusActionListener;
|
||||||
import com.keylesspalace.tusky.network.MastodonApi;
|
import com.keylesspalace.tusky.network.MastodonApi;
|
||||||
import com.keylesspalace.tusky.receiver.TimelineReceiver;
|
import com.keylesspalace.tusky.receiver.TimelineReceiver;
|
||||||
|
import com.keylesspalace.tusky.util.CollectionUtil;
|
||||||
|
import com.keylesspalace.tusky.util.Either;
|
||||||
import com.keylesspalace.tusky.util.HttpHeaderLink;
|
import com.keylesspalace.tusky.util.HttpHeaderLink;
|
||||||
import com.keylesspalace.tusky.util.ListUtils;
|
import com.keylesspalace.tusky.util.ListUtils;
|
||||||
import com.keylesspalace.tusky.util.PairedList;
|
import com.keylesspalace.tusky.util.PairedList;
|
||||||
|
@ -104,8 +108,18 @@ public class TimelineFragment extends SFragment implements
|
||||||
private String bottomId;
|
private String bottomId;
|
||||||
@Nullable
|
@Nullable
|
||||||
private String topId;
|
private String topId;
|
||||||
private PairedList<Status, StatusViewData> statuses =
|
private PairedList<Either<Placeholder, Status>, StatusViewData> statuses =
|
||||||
new PairedList<>(ViewDataUtils.statusMapper());
|
new PairedList<>(new Function<Either<Placeholder, Status>, StatusViewData>() {
|
||||||
|
@Override
|
||||||
|
public StatusViewData apply(Either<Placeholder, Status> input) {
|
||||||
|
Status status = input.getAsRightOrNull();
|
||||||
|
if (status != null) {
|
||||||
|
return ViewDataUtils.statusToViewData(status);
|
||||||
|
} else {
|
||||||
|
return new StatusViewData.Placeholder(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
public static TimelineFragment newInstance(Kind kind) {
|
public static TimelineFragment newInstance(Kind kind) {
|
||||||
TimelineFragment fragment = new TimelineFragment();
|
TimelineFragment fragment = new TimelineFragment();
|
||||||
|
@ -124,6 +138,17 @@ public class TimelineFragment extends SFragment implements
|
||||||
return fragment;
|
return fragment;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static final class Placeholder {
|
||||||
|
private final static Placeholder INSTANCE = new Placeholder();
|
||||||
|
|
||||||
|
public static Placeholder getInstance() {
|
||||||
|
return INSTANCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Placeholder() {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||||
Bundle savedInstanceState) {
|
Bundle savedInstanceState) {
|
||||||
|
@ -256,12 +281,12 @@ public class TimelineFragment extends SFragment implements
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onReply(int position) {
|
public void onReply(int position) {
|
||||||
super.reply(statuses.get(position));
|
super.reply(statuses.get(position).getAsRight());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onReblog(final boolean reblog, final int position) {
|
public void onReblog(final boolean reblog, final int position) {
|
||||||
final Status status = statuses.get(position);
|
final Status status = statuses.get(position).getAsRight();
|
||||||
super.reblogWithCallback(status, reblog, new Callback<Status>() {
|
super.reblogWithCallback(status, reblog, new Callback<Status>() {
|
||||||
@Override
|
@Override
|
||||||
public void onResponse(@NonNull Call<Status> call, @NonNull Response<Status> response) {
|
public void onResponse(@NonNull Call<Status> call, @NonNull Response<Status> response) {
|
||||||
|
@ -271,12 +296,17 @@ public class TimelineFragment extends SFragment implements
|
||||||
if (status.reblog != null) {
|
if (status.reblog != null) {
|
||||||
status.reblog.reblogged = reblog;
|
status.reblog.reblogged = reblog;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Pair<StatusViewData.Concrete, Integer> actual =
|
||||||
|
findStatusAndPosition(position, status);
|
||||||
|
if (actual == null) return;
|
||||||
|
|
||||||
StatusViewData newViewData =
|
StatusViewData newViewData =
|
||||||
new StatusViewData.Builder(statuses.getPairedItem(position))
|
new StatusViewData.Builder(actual.first)
|
||||||
.setReblogged(reblog)
|
.setReblogged(reblog)
|
||||||
.createStatusViewData();
|
.createStatusViewData();
|
||||||
statuses.setPairedItem(position, newViewData);
|
statuses.setPairedItem(actual.second, newViewData);
|
||||||
adapter.changeItem(position, newViewData, true);
|
adapter.changeItem(actual.second, newViewData, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -289,7 +319,7 @@ public class TimelineFragment extends SFragment implements
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onFavourite(final boolean favourite, final int position) {
|
public void onFavourite(final boolean favourite, final int position) {
|
||||||
final Status status = statuses.get(position);
|
final Status status = statuses.get(position).getAsRight();
|
||||||
|
|
||||||
super.favouriteWithCallback(status, favourite, new Callback<Status>() {
|
super.favouriteWithCallback(status, favourite, new Callback<Status>() {
|
||||||
@Override
|
@Override
|
||||||
|
@ -300,12 +330,17 @@ public class TimelineFragment extends SFragment implements
|
||||||
if (status.reblog != null) {
|
if (status.reblog != null) {
|
||||||
status.reblog.favourited = favourite;
|
status.reblog.favourited = favourite;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Pair<StatusViewData.Concrete, Integer> actual =
|
||||||
|
findStatusAndPosition(position, status);
|
||||||
|
if (actual == null) return;
|
||||||
|
|
||||||
StatusViewData newViewData = new StatusViewData
|
StatusViewData newViewData = new StatusViewData
|
||||||
.Builder(statuses.getPairedItem(position))
|
.Builder(actual.first)
|
||||||
.setFavourited(favourite)
|
.setFavourited(favourite)
|
||||||
.createStatusViewData();
|
.createStatusViewData();
|
||||||
statuses.setPairedItem(position, newViewData);
|
statuses.setPairedItem(actual.second, newViewData);
|
||||||
adapter.changeItem(position, newViewData, true);
|
adapter.changeItem(actual.second, newViewData, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -318,17 +353,18 @@ public class TimelineFragment extends SFragment implements
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onMore(View view, final int position) {
|
public void onMore(View view, final int position) {
|
||||||
super.more(statuses.get(position), view, position);
|
super.more(statuses.get(position).getAsRight(), view, position);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onOpenReblog(int position) {
|
public void onOpenReblog(int position) {
|
||||||
super.openReblog(statuses.get(position));
|
super.openReblog(statuses.get(position).getAsRight());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onExpandedChange(boolean expanded, int position) {
|
public void onExpandedChange(boolean expanded, int position) {
|
||||||
StatusViewData newViewData = new StatusViewData.Builder(statuses.getPairedItem(position))
|
StatusViewData newViewData = new StatusViewData.Builder(
|
||||||
|
((StatusViewData.Concrete) statuses.getPairedItem(position)))
|
||||||
.setIsExpanded(expanded).createStatusViewData();
|
.setIsExpanded(expanded).createStatusViewData();
|
||||||
statuses.setPairedItem(position, newViewData);
|
statuses.setPairedItem(position, newViewData);
|
||||||
adapter.changeItem(position, newViewData, false);
|
adapter.changeItem(position, newViewData, false);
|
||||||
|
@ -336,7 +372,8 @@ public class TimelineFragment extends SFragment implements
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onContentHiddenChange(boolean isShowing, int position) {
|
public void onContentHiddenChange(boolean isShowing, int position) {
|
||||||
StatusViewData newViewData = new StatusViewData.Builder(statuses.getPairedItem(position))
|
StatusViewData newViewData = new StatusViewData.Builder(
|
||||||
|
((StatusViewData.Concrete) statuses.getPairedItem(position)))
|
||||||
.setIsShowingSensitiveContent(isShowing).createStatusViewData();
|
.setIsShowingSensitiveContent(isShowing).createStatusViewData();
|
||||||
statuses.setPairedItem(position, newViewData);
|
statuses.setPairedItem(position, newViewData);
|
||||||
adapter.changeItem(position, newViewData, false);
|
adapter.changeItem(position, newViewData, false);
|
||||||
|
@ -346,17 +383,19 @@ public class TimelineFragment extends SFragment implements
|
||||||
public void onLoadMore(int position) {
|
public void onLoadMore(int position) {
|
||||||
//check bounds before accessing list,
|
//check bounds before accessing list,
|
||||||
if (statuses.size() >= position && position > 0) {
|
if (statuses.size() >= position && position > 0) {
|
||||||
String fromId = statuses.get(position - 1).id;
|
Status fromStatus = statuses.get(position - 1).getAsRightOrNull();
|
||||||
String toId = statuses.get(position + 1).id;
|
Status toStatus = statuses.get(position + 1).getAsRightOrNull();
|
||||||
sendFetchTimelineRequest(fromId, toId, FetchEnd.MIDDLE, position);
|
if (fromStatus == null || toStatus == null) {
|
||||||
|
Log.e(TAG, "Failed to load more at " + position + ", wrong placeholder position");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
sendFetchTimelineRequest(fromStatus.id, toStatus.id, FetchEnd.MIDDLE, position);
|
||||||
|
|
||||||
StatusViewData newViewData = new StatusViewData.Builder(statuses.getPairedItem(position))
|
StatusViewData newViewData = new StatusViewData.Placeholder(true);
|
||||||
.setPlaceholderLoading(true).createStatusViewData();
|
|
||||||
statuses.setPairedItem(position, newViewData);
|
statuses.setPairedItem(position, newViewData);
|
||||||
adapter.changeItem(position, newViewData, false);
|
adapter.changeItem(position, newViewData, false);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
Log.d(TAG, "error loading more");
|
Log.e(TAG, "error loading more");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -368,7 +407,7 @@ public class TimelineFragment extends SFragment implements
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onViewThread(int position) {
|
public void onViewThread(int position) {
|
||||||
super.viewThread(statuses.get(position));
|
super.viewThread(statuses.get(position).getAsRight());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -433,10 +472,10 @@ public class TimelineFragment extends SFragment implements
|
||||||
@Override
|
@Override
|
||||||
public void removeAllByAccountId(String accountId) {
|
public void removeAllByAccountId(String accountId) {
|
||||||
// using iterator to safely remove items while iterating
|
// using iterator to safely remove items while iterating
|
||||||
Iterator<Status> iterator = statuses.iterator();
|
Iterator<Either<Placeholder, Status>> iterator = statuses.iterator();
|
||||||
while (iterator.hasNext()) {
|
while (iterator.hasNext()) {
|
||||||
Status status = iterator.next();
|
Status status = iterator.next().getAsRightOrNull();
|
||||||
if (status.account.id.equals(accountId)) {
|
if (status != null && status.account.id.equals(accountId)) {
|
||||||
iterator.remove();
|
iterator.remove();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -534,6 +573,8 @@ public class TimelineFragment extends SFragment implements
|
||||||
|
|
||||||
private void onFetchTimelineSuccess(List<Status> statuses, String linkHeader,
|
private void onFetchTimelineSuccess(List<Status> statuses, String linkHeader,
|
||||||
FetchEnd fetchEnd, int pos) {
|
FetchEnd fetchEnd, int pos) {
|
||||||
|
// We filled the hole (or reached the end) if the server returned less statuses than we
|
||||||
|
// we asked for.
|
||||||
boolean fullFetch = statuses.size() >= LOAD_AT_ONCE;
|
boolean fullFetch = statuses.size() >= LOAD_AT_ONCE;
|
||||||
filterStatuses(statuses);
|
filterStatuses(statuses);
|
||||||
List<HttpHeaderLink> links = HttpHeaderLink.parse(linkHeader);
|
List<HttpHeaderLink> links = HttpHeaderLink.parse(linkHeader);
|
||||||
|
@ -548,7 +589,7 @@ public class TimelineFragment extends SFragment implements
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case MIDDLE: {
|
case MIDDLE: {
|
||||||
insertStatuses(statuses,fullFetch, pos);
|
replacePlaceholderWithStatuses(statuses, fullFetch, pos);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case BOTTOM: {
|
case BOTTOM: {
|
||||||
|
@ -585,10 +626,8 @@ public class TimelineFragment extends SFragment implements
|
||||||
private void onFetchTimelineFailure(Exception exception, FetchEnd fetchEnd, int position) {
|
private void onFetchTimelineFailure(Exception exception, FetchEnd fetchEnd, int position) {
|
||||||
swipeRefreshLayout.setRefreshing(false);
|
swipeRefreshLayout.setRefreshing(false);
|
||||||
|
|
||||||
if(fetchEnd == FetchEnd.MIDDLE && statuses.getPairedItem(position).isPlaceholder()) {
|
if (fetchEnd == FetchEnd.MIDDLE && !statuses.get(position).isRight()) {
|
||||||
|
StatusViewData newViewData = new StatusViewData.Placeholder(true);
|
||||||
StatusViewData newViewData = new StatusViewData.Builder(statuses.getPairedItem(position))
|
|
||||||
.setPlaceholderLoading(false).createStatusViewData();
|
|
||||||
statuses.setPairedItem(position, newViewData);
|
statuses.setPairedItem(position, newViewData);
|
||||||
adapter.changeItem(position, newViewData, true);
|
adapter.changeItem(position, newViewData, true);
|
||||||
}
|
}
|
||||||
|
@ -640,25 +679,26 @@ public class TimelineFragment extends SFragment implements
|
||||||
if (toId != null) {
|
if (toId != null) {
|
||||||
topId = toId;
|
topId = toId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
List<Either<Placeholder, Status>> liftedNew = listStatusList(newStatuses);
|
||||||
|
|
||||||
if (statuses.isEmpty()) {
|
if (statuses.isEmpty()) {
|
||||||
statuses.addAll(newStatuses);
|
statuses.addAll(liftedNew);
|
||||||
} else {
|
} else {
|
||||||
Status lastOfNew = newStatuses.get(newStatuses.size() - 1);
|
Either<Placeholder, Status> lastOfNew = liftedNew.get(newStatuses.size() - 1);
|
||||||
int index = statuses.indexOf(lastOfNew);
|
int index = statuses.indexOf(lastOfNew);
|
||||||
|
|
||||||
for (int i = 0; i < index; i++) {
|
for (int i = 0; i < index; i++) {
|
||||||
statuses.remove(0);
|
statuses.remove(0);
|
||||||
}
|
}
|
||||||
int newIndex = newStatuses.indexOf(statuses.get(0));
|
int newIndex = liftedNew.indexOf(statuses.get(0));
|
||||||
if (newIndex == -1) {
|
if (newIndex == -1) {
|
||||||
if(index == -1 && fullFetch) {
|
if (index == -1 && fullFetch) {
|
||||||
Status placeholder = new Status();
|
liftedNew.add(Either.<Placeholder, Status>left(Placeholder.getInstance()));
|
||||||
placeholder.placeholder = true;
|
|
||||||
newStatuses.add(placeholder);
|
|
||||||
}
|
}
|
||||||
statuses.addAll(0, newStatuses);
|
statuses.addAll(0, liftedNew);
|
||||||
} else {
|
} else {
|
||||||
statuses.addAll(0, newStatuses.subList(0, newIndex));
|
statuses.addAll(0, liftedNew.subList(0, newIndex));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
adapter.update(statuses.getPairedCopy());
|
adapter.update(statuses.getPairedCopy());
|
||||||
|
@ -669,9 +709,11 @@ public class TimelineFragment extends SFragment implements
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
int end = statuses.size();
|
int end = statuses.size();
|
||||||
Status last = statuses.get(end - 1);
|
Status last = statuses.get(end - 1).getAsRightOrNull();
|
||||||
|
// I was about to replace findStatus with indexOf but it is incorrect to compare value
|
||||||
|
// types by ID anyway and we should change equals() for Status, I think, so this makes sense
|
||||||
if (last != null && !findStatus(newStatuses, last.id)) {
|
if (last != null && !findStatus(newStatuses, last.id)) {
|
||||||
statuses.addAll(newStatuses);
|
statuses.addAll(listStatusList(newStatuses));
|
||||||
List<StatusViewData> newViewDatas = statuses.getPairedCopy()
|
List<StatusViewData> newViewDatas = statuses.getPairedCopy()
|
||||||
.subList(statuses.size() - newStatuses.size(), statuses.size());
|
.subList(statuses.size() - newStatuses.size(), statuses.size());
|
||||||
if (BuildConfig.DEBUG && newStatuses.size() != newViewDatas.size()) {
|
if (BuildConfig.DEBUG && newStatuses.size() != newViewDatas.size()) {
|
||||||
|
@ -688,9 +730,9 @@ public class TimelineFragment extends SFragment implements
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void insertStatuses(List<Status> newStatuses, boolean fullFetch, int pos) {
|
private void replacePlaceholderWithStatuses(List<Status> newStatuses, boolean fullFetch, int pos) {
|
||||||
|
Status status = statuses.get(pos).getAsRightOrNull();
|
||||||
if(statuses.get(pos).placeholder) {
|
if (status == null) {
|
||||||
statuses.remove(pos);
|
statuses.remove(pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -699,13 +741,13 @@ public class TimelineFragment extends SFragment implements
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(fullFetch) {
|
List<Either<Placeholder, Status>> liftedNew = listStatusList(newStatuses);
|
||||||
Status placeholder = new Status();
|
|
||||||
placeholder.placeholder = true;
|
if (fullFetch) {
|
||||||
newStatuses.add(placeholder);
|
liftedNew.add(Either.<Placeholder, Status>left(Placeholder.getInstance()));
|
||||||
}
|
}
|
||||||
|
|
||||||
statuses.addAll(pos, newStatuses);
|
statuses.addAll(pos, liftedNew);
|
||||||
adapter.update(statuses.getPairedCopy());
|
adapter.update(statuses.getPairedCopy());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -718,4 +760,39 @@ public class TimelineFragment extends SFragment implements
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private final Function<Status, Either<Placeholder, Status>> statusLifter =
|
||||||
|
new Function<Status, Either<Placeholder, Status>>() {
|
||||||
|
@Override
|
||||||
|
public Either<Placeholder, Status> apply(Status input) {
|
||||||
|
return Either.right(input);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private @Nullable
|
||||||
|
Pair<StatusViewData.Concrete, Integer>
|
||||||
|
findStatusAndPosition(int position, Status status) {
|
||||||
|
StatusViewData.Concrete statusToUpdate;
|
||||||
|
int positionToUpdate;
|
||||||
|
StatusViewData someOldViewData = statuses.getPairedItem(position);
|
||||||
|
|
||||||
|
// Unlikely, but data could change between the request and response
|
||||||
|
if ((someOldViewData instanceof StatusViewData.Placeholder) ||
|
||||||
|
!((StatusViewData.Concrete) someOldViewData).getId().equals(status.id)) {
|
||||||
|
// try to find the status we need to update
|
||||||
|
int foundPos = statuses.indexOf(Either.<Placeholder, Status>right(status));
|
||||||
|
if (foundPos < 0) return null; // okay, it's hopeless, give up
|
||||||
|
statusToUpdate = ((StatusViewData.Concrete)
|
||||||
|
statuses.getPairedItem(foundPos));
|
||||||
|
positionToUpdate = position;
|
||||||
|
} else {
|
||||||
|
statusToUpdate = (StatusViewData.Concrete) someOldViewData;
|
||||||
|
positionToUpdate = position;
|
||||||
|
}
|
||||||
|
return new Pair<>(statusToUpdate, positionToUpdate);
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<Either<Placeholder, Status>> listStatusList(List<Status> list) {
|
||||||
|
return CollectionUtil.map(list, statusLifter);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -69,7 +69,7 @@ public class ViewThreadFragment extends SFragment implements
|
||||||
|
|
||||||
private int statusIndex = 0;
|
private int statusIndex = 0;
|
||||||
|
|
||||||
private final PairedList<Status, StatusViewData> statuses =
|
private final PairedList<Status, StatusViewData.Concrete> statuses =
|
||||||
new PairedList<>(ViewDataUtils.statusMapper());
|
new PairedList<>(ViewDataUtils.statusMapper());
|
||||||
|
|
||||||
public static ViewThreadFragment newInstance(String id) {
|
public static ViewThreadFragment newInstance(String id) {
|
||||||
|
@ -83,7 +83,7 @@ public class ViewThreadFragment extends SFragment implements
|
||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
|
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
|
||||||
@Nullable Bundle savedInstanceState) {
|
@Nullable Bundle savedInstanceState) {
|
||||||
View rootView = inflater.inflate(R.layout.fragment_view_thread, container, false);
|
View rootView = inflater.inflate(R.layout.fragment_view_thread, container, false);
|
||||||
|
|
||||||
Context context = getContext();
|
Context context = getContext();
|
||||||
|
@ -227,18 +227,20 @@ public class ViewThreadFragment extends SFragment implements
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onExpandedChange(boolean expanded, int position) {
|
public void onExpandedChange(boolean expanded, int position) {
|
||||||
StatusViewData newViewData = new StatusViewData.Builder(statuses.getPairedItem(position))
|
StatusViewData.Concrete newViewData =
|
||||||
.setIsExpanded(expanded)
|
new StatusViewData.Builder(statuses.getPairedItem(position))
|
||||||
.createStatusViewData();
|
.setIsExpanded(expanded)
|
||||||
|
.createStatusViewData();
|
||||||
statuses.setPairedItem(position, newViewData);
|
statuses.setPairedItem(position, newViewData);
|
||||||
adapter.setItem(position, newViewData, false);
|
adapter.setItem(position, newViewData, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onContentHiddenChange(boolean isShowing, int position) {
|
public void onContentHiddenChange(boolean isShowing, int position) {
|
||||||
StatusViewData newViewData = new StatusViewData.Builder(statuses.getPairedItem(position))
|
StatusViewData.Concrete newViewData =
|
||||||
.setIsShowingSensitiveContent(isShowing)
|
new StatusViewData.Builder(statuses.getPairedItem(position))
|
||||||
.createStatusViewData();
|
.setIsShowingSensitiveContent(isShowing)
|
||||||
|
.createStatusViewData();
|
||||||
statuses.setPairedItem(position, newViewData);
|
statuses.setPairedItem(position, newViewData);
|
||||||
adapter.setItem(position, newViewData, false);
|
adapter.setItem(position, newViewData, false);
|
||||||
}
|
}
|
||||||
|
@ -260,7 +262,7 @@ public class ViewThreadFragment extends SFragment implements
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void removeItem(int position) {
|
public void removeItem(int position) {
|
||||||
if(position == statusIndex) {
|
if (position == statusIndex) {
|
||||||
//the status got removed, close the activity
|
//the status got removed, close the activity
|
||||||
getActivity().finish();
|
getActivity().finish();
|
||||||
}
|
}
|
||||||
|
@ -283,7 +285,7 @@ public class ViewThreadFragment extends SFragment implements
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
statusIndex = statuses.indexOf(status);
|
statusIndex = statuses.indexOf(status);
|
||||||
if(statusIndex == -1) {
|
if (statusIndex == -1) {
|
||||||
//the status got removed, close the activity
|
//the status got removed, close the activity
|
||||||
getActivity().finish();
|
getActivity().finish();
|
||||||
return;
|
return;
|
||||||
|
@ -384,8 +386,8 @@ public class ViewThreadFragment extends SFragment implements
|
||||||
int i = statusIndex;
|
int i = statusIndex;
|
||||||
statuses.add(i, status);
|
statuses.add(i, status);
|
||||||
adapter.setDetailedStatusPosition(i);
|
adapter.setDetailedStatusPosition(i);
|
||||||
StatusViewData viewData = statuses.getPairedItem(i);
|
StatusViewData.Concrete viewData = statuses.getPairedItem(i);
|
||||||
if(viewData.getCard() == null && card != null) {
|
if (viewData.getCard() == null && card != null) {
|
||||||
viewData = new StatusViewData.Builder(viewData)
|
viewData = new StatusViewData.Builder(viewData)
|
||||||
.setCard(card)
|
.setCard(card)
|
||||||
.createStatusViewData();
|
.createStatusViewData();
|
||||||
|
@ -410,7 +412,7 @@ public class ViewThreadFragment extends SFragment implements
|
||||||
statusIndex = ancestors.size();
|
statusIndex = ancestors.size();
|
||||||
adapter.setDetailedStatusPosition(statusIndex);
|
adapter.setDetailedStatusPosition(statusIndex);
|
||||||
statuses.addAll(0, ancestors);
|
statuses.addAll(0, ancestors);
|
||||||
List<StatusViewData> ancestorsViewDatas = statuses.getPairedCopy().subList(0, statusIndex);
|
List<StatusViewData.Concrete> ancestorsViewDatas = statuses.getPairedCopy().subList(0, statusIndex);
|
||||||
if (BuildConfig.DEBUG && ancestors.size() != ancestorsViewDatas.size()) {
|
if (BuildConfig.DEBUG && ancestors.size() != ancestorsViewDatas.size()) {
|
||||||
String error = String.format(Locale.getDefault(),
|
String error = String.format(Locale.getDefault(),
|
||||||
"Incorrectly got statusViewData sublist." +
|
"Incorrectly got statusViewData sublist." +
|
||||||
|
@ -425,8 +427,8 @@ public class ViewThreadFragment extends SFragment implements
|
||||||
// In case we needed to delete everything (which is way easier than deleting
|
// In case we needed to delete everything (which is way easier than deleting
|
||||||
// everything except one), re-insert the remaining status here.
|
// everything except one), re-insert the remaining status here.
|
||||||
statuses.add(statusIndex, mainStatus);
|
statuses.add(statusIndex, mainStatus);
|
||||||
StatusViewData viewData = statuses.getPairedItem(statusIndex);
|
StatusViewData.Concrete viewData = statuses.getPairedItem(statusIndex);
|
||||||
if(viewData.getCard() == null && card != null) {
|
if (viewData.getCard() == null && card != null) {
|
||||||
viewData = new StatusViewData.Builder(viewData)
|
viewData = new StatusViewData.Builder(viewData)
|
||||||
.setCard(card)
|
.setCard(card)
|
||||||
.createStatusViewData();
|
.createStatusViewData();
|
||||||
|
@ -436,9 +438,9 @@ public class ViewThreadFragment extends SFragment implements
|
||||||
|
|
||||||
// Insert newly fetched descendants
|
// Insert newly fetched descendants
|
||||||
statuses.addAll(descendants);
|
statuses.addAll(descendants);
|
||||||
List<StatusViewData> descendantsViewData;
|
List<StatusViewData.Concrete> descendantsViewData;
|
||||||
descendantsViewData = statuses.getPairedCopy()
|
descendantsViewData = statuses.getPairedCopy()
|
||||||
.subList(statuses.size() - descendants.size(), statuses.size());
|
.subList(statuses.size() - descendants.size(), statuses.size());
|
||||||
if (BuildConfig.DEBUG && descendants.size() != descendantsViewData.size()) {
|
if (BuildConfig.DEBUG && descendants.size() != descendantsViewData.size()) {
|
||||||
String error = String.format(Locale.getDefault(),
|
String error = String.format(Locale.getDefault(),
|
||||||
"Incorrectly got statusViewData sublist." +
|
"Incorrectly got statusViewData sublist." +
|
||||||
|
@ -452,16 +454,14 @@ public class ViewThreadFragment extends SFragment implements
|
||||||
|
|
||||||
private void showCard(Card card) {
|
private void showCard(Card card) {
|
||||||
this.card = card;
|
this.card = card;
|
||||||
if(statuses.size() != 0) {
|
if (statuses.size() != 0) {
|
||||||
StatusViewData oldViewData = statuses.getPairedItem(statusIndex);
|
StatusViewData.Concrete newViewData =
|
||||||
if(oldViewData != null) {
|
new StatusViewData.Builder(statuses.getPairedItem(statusIndex))
|
||||||
StatusViewData newViewData = new StatusViewData.Builder(statuses.getPairedItem(statusIndex))
|
.setCard(card)
|
||||||
.setCard(card)
|
.createStatusViewData();
|
||||||
.createStatusViewData();
|
|
||||||
|
|
||||||
statuses.setPairedItem(statusIndex, newViewData);
|
statuses.setPairedItem(statusIndex, newViewData);
|
||||||
adapter.setItem(statusIndex, newViewData, true);
|
adapter.setItem(statusIndex, newViewData, true);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -32,13 +32,8 @@ import java.util.List;
|
||||||
|
|
||||||
public final class ViewDataUtils {
|
public final class ViewDataUtils {
|
||||||
@Nullable
|
@Nullable
|
||||||
public static StatusViewData statusToViewData(@Nullable Status status) {
|
public static StatusViewData.Concrete statusToViewData(@Nullable Status status) {
|
||||||
if (status == null) return null;
|
if (status == null) return null;
|
||||||
if (status.placeholder) {
|
|
||||||
return new StatusViewData.Builder().setId(status.id)
|
|
||||||
.setPlaceholder(true)
|
|
||||||
.createStatusViewData();
|
|
||||||
}
|
|
||||||
Status visibleStatus = status.reblog == null ? status : status.reblog;
|
Status visibleStatus = status.reblog == null ? status : status.reblog;
|
||||||
return new StatusViewData.Builder().setId(status.id)
|
return new StatusViewData.Builder().setId(status.id)
|
||||||
.setAttachments(visibleStatus.attachments)
|
.setAttachments(visibleStatus.attachments)
|
||||||
|
@ -75,11 +70,11 @@ public final class ViewDataUtils {
|
||||||
return viewDatas;
|
return viewDatas;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Function<Status, StatusViewData> statusMapper() {
|
public static Function<Status, StatusViewData.Concrete> statusMapper() {
|
||||||
return statusMapper;
|
return statusMapper;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static NotificationViewData notificationToViewData(Notification notification) {
|
public static NotificationViewData.Concrete notificationToViewData(Notification notification) {
|
||||||
return new NotificationViewData.Concrete(notification.type, notification.id, notification.account,
|
return new NotificationViewData.Concrete(notification.type, notification.id, notification.account,
|
||||||
statusToViewData(notification.status));
|
statusToViewData(notification.status));
|
||||||
}
|
}
|
||||||
|
@ -93,10 +88,10 @@ public final class ViewDataUtils {
|
||||||
return viewDatas;
|
return viewDatas;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final Function<Status, StatusViewData> statusMapper =
|
private static final Function<Status, StatusViewData.Concrete> statusMapper =
|
||||||
new Function<Status, StatusViewData>() {
|
new Function<Status, StatusViewData.Concrete>() {
|
||||||
@Override
|
@Override
|
||||||
public StatusViewData apply(Status input) {
|
public StatusViewData.Concrete apply(Status input) {
|
||||||
return ViewDataUtils.statusToViewData(input);
|
return ViewDataUtils.statusToViewData(input);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -49,16 +49,16 @@ public class ConversationLineItemDecoration extends RecyclerView.ItemDecoration
|
||||||
|
|
||||||
int position = parent.getChildAdapterPosition(child);
|
int position = parent.getChildAdapterPosition(child);
|
||||||
ThreadAdapter adapter = (ThreadAdapter) parent.getAdapter();
|
ThreadAdapter adapter = (ThreadAdapter) parent.getAdapter();
|
||||||
StatusViewData current = adapter.getItem(position);
|
StatusViewData.Concrete current = adapter.getItem(position);
|
||||||
int dividerTop, dividerBottom;
|
int dividerTop, dividerBottom;
|
||||||
if (current != null) {
|
if (current != null) {
|
||||||
StatusViewData above = adapter.getItem(position - 1);
|
StatusViewData.Concrete above = adapter.getItem(position - 1);
|
||||||
if (above != null && above.getId().equals(current.getInReplyToId())) {
|
if (above != null && above.getId().equals(current.getInReplyToId())) {
|
||||||
dividerTop = child.getTop();
|
dividerTop = child.getTop();
|
||||||
} else {
|
} else {
|
||||||
dividerTop = child.getTop() + avatarMargin;
|
dividerTop = child.getTop() + avatarMargin;
|
||||||
}
|
}
|
||||||
StatusViewData below = adapter.getItem(position + 1);
|
StatusViewData.Concrete below = adapter.getItem(position + 1);
|
||||||
if (below != null && current.getId().equals(below.getInReplyToId())) {
|
if (below != null && current.getId().equals(below.getInReplyToId())) {
|
||||||
dividerBottom = child.getBottom();
|
dividerBottom = child.getBottom();
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -37,10 +37,10 @@ public abstract class NotificationViewData {
|
||||||
private final Notification.Type type;
|
private final Notification.Type type;
|
||||||
private final String id;
|
private final String id;
|
||||||
private final Account account;
|
private final Account account;
|
||||||
private final StatusViewData statusViewData;
|
private final StatusViewData.Concrete statusViewData;
|
||||||
|
|
||||||
public Concrete(Notification.Type type, String id, Account account,
|
public Concrete(Notification.Type type, String id, Account account,
|
||||||
StatusViewData statusViewData) {
|
StatusViewData.Concrete statusViewData) {
|
||||||
this.type = type;
|
this.type = type;
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.account = account;
|
this.account = account;
|
||||||
|
@ -59,7 +59,7 @@ public abstract class NotificationViewData {
|
||||||
return account;
|
return account;
|
||||||
}
|
}
|
||||||
|
|
||||||
public StatusViewData getStatusViewData() {
|
public StatusViewData.Concrete getStatusViewData() {
|
||||||
return statusViewData;
|
return statusViewData;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,195 +27,202 @@ import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by charlag on 11/07/2017.
|
* Created by charlag on 11/07/2017.
|
||||||
|
*
|
||||||
|
* Class to represent data required to display either a notification or a placeholder.
|
||||||
|
* It is either a {@link StatusViewData.Concrete} or a {@link StatusViewData.Placeholder}.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public final class StatusViewData {
|
public abstract class StatusViewData {
|
||||||
private final String id;
|
|
||||||
private final Spanned content;
|
|
||||||
private final boolean reblogged;
|
|
||||||
private final boolean favourited;
|
|
||||||
@Nullable
|
|
||||||
private final String spoilerText;
|
|
||||||
private final Status.Visibility visibility;
|
|
||||||
private final Status.MediaAttachment[] attachments;
|
|
||||||
@Nullable
|
|
||||||
private final String rebloggedByUsername;
|
|
||||||
@Nullable
|
|
||||||
private final String rebloggedAvatar;
|
|
||||||
private final boolean isSensitive;
|
|
||||||
private final boolean isExpanded;
|
|
||||||
private final boolean isShowingSensitiveContent;
|
|
||||||
private final String userFullName;
|
|
||||||
private final String nickname;
|
|
||||||
private final String avatar;
|
|
||||||
private final Date createdAt;
|
|
||||||
private final String reblogsCount;
|
|
||||||
private final String favouritesCount;
|
|
||||||
@Nullable
|
|
||||||
private final String inReplyToId;
|
|
||||||
// I would rather have something else but it would be too much of a rewrite
|
|
||||||
@Nullable
|
|
||||||
private final Status.Mention[] mentions;
|
|
||||||
private final String senderId;
|
|
||||||
private final boolean rebloggingEnabled;
|
|
||||||
private final Status.Application application;
|
|
||||||
private final List<Status.Emoji> emojis;
|
|
||||||
@Nullable
|
|
||||||
private final Card card;
|
|
||||||
|
|
||||||
private final boolean placeholder;
|
private StatusViewData() {
|
||||||
|
|
||||||
private final boolean placeholderLoading;
|
|
||||||
|
|
||||||
public StatusViewData(String id, Spanned content, boolean reblogged, boolean favourited,
|
|
||||||
@Nullable String spoilerText, Status.Visibility visibility, Status.MediaAttachment[] attachments,
|
|
||||||
@Nullable String rebloggedByUsername, @Nullable String rebloggedAvatar, boolean sensitive, boolean isExpanded,
|
|
||||||
boolean isShowingSensitiveWarning, String userFullName, String nickname, String avatar,
|
|
||||||
Date createdAt, String reblogsCount, String favouritesCount, @Nullable String inReplyToId,
|
|
||||||
@Nullable Status.Mention[] mentions, String senderId, boolean rebloggingEnabled,
|
|
||||||
Status.Application application, List<Status.Emoji> emojis, @Nullable Card card,
|
|
||||||
boolean placeholder, boolean placeholderLoading) {
|
|
||||||
this.id = id;
|
|
||||||
this.content = content;
|
|
||||||
this.reblogged = reblogged;
|
|
||||||
this.favourited = favourited;
|
|
||||||
this.spoilerText = spoilerText;
|
|
||||||
this.visibility = visibility;
|
|
||||||
this.attachments = attachments;
|
|
||||||
this.rebloggedByUsername = rebloggedByUsername;
|
|
||||||
this.rebloggedAvatar = rebloggedAvatar;
|
|
||||||
this.isSensitive = sensitive;
|
|
||||||
this.isExpanded = isExpanded;
|
|
||||||
this.isShowingSensitiveContent = isShowingSensitiveWarning;
|
|
||||||
this.userFullName = userFullName;
|
|
||||||
this.nickname = nickname;
|
|
||||||
this.avatar = avatar;
|
|
||||||
this.createdAt = createdAt;
|
|
||||||
this.reblogsCount = reblogsCount;
|
|
||||||
this.favouritesCount = favouritesCount;
|
|
||||||
this.inReplyToId = inReplyToId;
|
|
||||||
this.mentions = mentions;
|
|
||||||
this.senderId = senderId;
|
|
||||||
this.rebloggingEnabled = rebloggingEnabled;
|
|
||||||
this.application = application;
|
|
||||||
this.emojis = emojis;
|
|
||||||
this.card = card;
|
|
||||||
this.placeholder = placeholder;
|
|
||||||
this.placeholderLoading = placeholderLoading;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getId() {
|
public static final class Concrete extends StatusViewData {
|
||||||
return id;
|
private final String id;
|
||||||
|
private final Spanned content;
|
||||||
|
private final boolean reblogged;
|
||||||
|
private final boolean favourited;
|
||||||
|
@Nullable
|
||||||
|
private final String spoilerText;
|
||||||
|
private final Status.Visibility visibility;
|
||||||
|
private final Status.MediaAttachment[] attachments;
|
||||||
|
@Nullable
|
||||||
|
private final String rebloggedByUsername;
|
||||||
|
@Nullable
|
||||||
|
private final String rebloggedAvatar;
|
||||||
|
private final boolean isSensitive;
|
||||||
|
private final boolean isExpanded;
|
||||||
|
private final boolean isShowingSensitiveContent;
|
||||||
|
private final String userFullName;
|
||||||
|
private final String nickname;
|
||||||
|
private final String avatar;
|
||||||
|
private final Date createdAt;
|
||||||
|
private final String reblogsCount;
|
||||||
|
private final String favouritesCount;
|
||||||
|
@Nullable
|
||||||
|
private final String inReplyToId;
|
||||||
|
// I would rather have something else but it would be too much of a rewrite
|
||||||
|
@Nullable
|
||||||
|
private final Status.Mention[] mentions;
|
||||||
|
private final String senderId;
|
||||||
|
private final boolean rebloggingEnabled;
|
||||||
|
private final Status.Application application;
|
||||||
|
private final List<Status.Emoji> emojis;
|
||||||
|
@Nullable
|
||||||
|
private final Card card;
|
||||||
|
|
||||||
|
public Concrete(String id, Spanned content, boolean reblogged, boolean favourited,
|
||||||
|
@Nullable String spoilerText, Status.Visibility visibility, Status.MediaAttachment[] attachments,
|
||||||
|
@Nullable String rebloggedByUsername, @Nullable String rebloggedAvatar, boolean sensitive, boolean isExpanded,
|
||||||
|
boolean isShowingSensitiveWarning, String userFullName, String nickname, String avatar,
|
||||||
|
Date createdAt, String reblogsCount, String favouritesCount, @Nullable String inReplyToId,
|
||||||
|
@Nullable Status.Mention[] mentions, String senderId, boolean rebloggingEnabled,
|
||||||
|
Status.Application application, List<Status.Emoji> emojis, @Nullable Card card) {
|
||||||
|
this.id = id;
|
||||||
|
this.content = content;
|
||||||
|
this.reblogged = reblogged;
|
||||||
|
this.favourited = favourited;
|
||||||
|
this.spoilerText = spoilerText;
|
||||||
|
this.visibility = visibility;
|
||||||
|
this.attachments = attachments;
|
||||||
|
this.rebloggedByUsername = rebloggedByUsername;
|
||||||
|
this.rebloggedAvatar = rebloggedAvatar;
|
||||||
|
this.isSensitive = sensitive;
|
||||||
|
this.isExpanded = isExpanded;
|
||||||
|
this.isShowingSensitiveContent = isShowingSensitiveWarning;
|
||||||
|
this.userFullName = userFullName;
|
||||||
|
this.nickname = nickname;
|
||||||
|
this.avatar = avatar;
|
||||||
|
this.createdAt = createdAt;
|
||||||
|
this.reblogsCount = reblogsCount;
|
||||||
|
this.favouritesCount = favouritesCount;
|
||||||
|
this.inReplyToId = inReplyToId;
|
||||||
|
this.mentions = mentions;
|
||||||
|
this.senderId = senderId;
|
||||||
|
this.rebloggingEnabled = rebloggingEnabled;
|
||||||
|
this.application = application;
|
||||||
|
this.emojis = emojis;
|
||||||
|
this.card = card;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Spanned getContent() {
|
||||||
|
return content;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isReblogged() {
|
||||||
|
return reblogged;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isFavourited() {
|
||||||
|
return favourited;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public String getSpoilerText() {
|
||||||
|
return spoilerText;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Status.Visibility getVisibility() {
|
||||||
|
return visibility;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Status.MediaAttachment[] getAttachments() {
|
||||||
|
return attachments;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public String getRebloggedByUsername() {
|
||||||
|
return rebloggedByUsername;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isSensitive() {
|
||||||
|
return isSensitive;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isExpanded() {
|
||||||
|
return isExpanded;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isShowingSensitiveContent() {
|
||||||
|
return isShowingSensitiveContent;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public String getRebloggedAvatar() {
|
||||||
|
return rebloggedAvatar;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUserFullName() {
|
||||||
|
return userFullName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getNickname() {
|
||||||
|
return nickname;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAvatar() {
|
||||||
|
return avatar;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Date getCreatedAt() {
|
||||||
|
return createdAt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getReblogsCount() {
|
||||||
|
return reblogsCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getFavouritesCount() {
|
||||||
|
return favouritesCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public String getInReplyToId() {
|
||||||
|
return inReplyToId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSenderId() {
|
||||||
|
return senderId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Boolean getRebloggingEnabled() {
|
||||||
|
return rebloggingEnabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public Status.Mention[] getMentions() {
|
||||||
|
return mentions;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Status.Application getApplication() {
|
||||||
|
return application;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Status.Emoji> getEmojis() {
|
||||||
|
return emojis;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public Card getCard() {
|
||||||
|
return card;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Spanned getContent() {
|
public static final class Placeholder extends StatusViewData {
|
||||||
return content;
|
private final boolean isLoading;
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isReblogged() {
|
public Placeholder(boolean isLoading) {
|
||||||
return reblogged;
|
this.isLoading = isLoading;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isFavourited() {
|
public boolean isLoading() {
|
||||||
return favourited;
|
return isLoading;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
|
||||||
public String getSpoilerText() {
|
|
||||||
return spoilerText;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Status.Visibility getVisibility() {
|
|
||||||
return visibility;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Status.MediaAttachment[] getAttachments() {
|
|
||||||
return attachments;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
public String getRebloggedByUsername() {
|
|
||||||
return rebloggedByUsername;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isSensitive() {
|
|
||||||
return isSensitive;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isExpanded() {
|
|
||||||
return isExpanded;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isShowingSensitiveContent() {
|
|
||||||
return isShowingSensitiveContent;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
public String getRebloggedAvatar() {
|
|
||||||
return rebloggedAvatar;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getUserFullName() {
|
|
||||||
return userFullName;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getNickname() {
|
|
||||||
return nickname;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getAvatar() {
|
|
||||||
return avatar;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Date getCreatedAt() {
|
|
||||||
return createdAt;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getReblogsCount() {
|
|
||||||
return reblogsCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getFavouritesCount() {
|
|
||||||
return favouritesCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
public String getInReplyToId() {
|
|
||||||
return inReplyToId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getSenderId() {
|
|
||||||
return senderId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Boolean getRebloggingEnabled() {
|
|
||||||
return rebloggingEnabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
public Status.Mention[] getMentions() {
|
|
||||||
return mentions;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Status.Application getApplication() {
|
|
||||||
return application;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<Status.Emoji> getEmojis() {
|
|
||||||
return emojis;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
public Card getCard() {
|
|
||||||
return card;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isPlaceholder() {
|
|
||||||
return placeholder;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isPlaceholderLoading() {
|
|
||||||
return placeholderLoading;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class Builder {
|
public static class Builder {
|
||||||
|
@ -244,13 +251,11 @@ public final class StatusViewData {
|
||||||
private Status.Application application;
|
private Status.Application application;
|
||||||
private List<Status.Emoji> emojis;
|
private List<Status.Emoji> emojis;
|
||||||
private Card card;
|
private Card card;
|
||||||
private boolean placeholder;
|
|
||||||
private boolean placeholderLoading;
|
|
||||||
|
|
||||||
public Builder() {
|
public Builder() {
|
||||||
}
|
}
|
||||||
|
|
||||||
public Builder(final StatusViewData viewData) {
|
public Builder(final StatusViewData.Concrete viewData) {
|
||||||
id = viewData.id;
|
id = viewData.id;
|
||||||
content = viewData.content;
|
content = viewData.content;
|
||||||
reblogged = viewData.reblogged;
|
reblogged = viewData.reblogged;
|
||||||
|
@ -276,9 +281,6 @@ public final class StatusViewData {
|
||||||
application = viewData.application;
|
application = viewData.application;
|
||||||
emojis = viewData.getEmojis();
|
emojis = viewData.getEmojis();
|
||||||
card = viewData.getCard();
|
card = viewData.getCard();
|
||||||
placeholder = viewData.isPlaceholder();
|
|
||||||
placeholderLoading = viewData.isPlaceholderLoading();
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Builder setId(String id) {
|
public Builder setId(String id) {
|
||||||
|
@ -406,25 +408,15 @@ public final class StatusViewData {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Builder setPlaceholder(boolean placeholder) {
|
public StatusViewData.Concrete createStatusViewData() {
|
||||||
this.placeholder = placeholder;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Builder setPlaceholderLoading(boolean placeholderLoading) {
|
|
||||||
this.placeholderLoading = placeholderLoading;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public StatusViewData createStatusViewData() {
|
|
||||||
if (this.emojis == null) emojis = Collections.emptyList();
|
if (this.emojis == null) emojis = Collections.emptyList();
|
||||||
if (this.createdAt == null) createdAt = new Date();
|
if (this.createdAt == null) createdAt = new Date();
|
||||||
|
|
||||||
return new StatusViewData(id, content, reblogged, favourited, spoilerText, visibility,
|
return new StatusViewData.Concrete(id, content, reblogged, favourited, spoilerText, visibility,
|
||||||
attachments, rebloggedByUsername, rebloggedAvatar, isSensitive, isExpanded,
|
attachments, rebloggedByUsername, rebloggedAvatar, isSensitive, isExpanded,
|
||||||
isShowingSensitiveContent, userFullName, nickname, avatar, createdAt, reblogsCount,
|
isShowingSensitiveContent, userFullName, nickname, avatar, createdAt, reblogsCount,
|
||||||
favouritesCount, inReplyToId, mentions, senderId, rebloggingEnabled, application,
|
favouritesCount, inReplyToId, mentions, senderId, rebloggingEnabled, application,
|
||||||
emojis, card, placeholder, placeholderLoading);
|
emojis, card);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue