Make status placeholder abstraction cleaner

This commit is contained in:
charlag 2017-11-06 18:19:15 +03:00 committed by Konrad Pozniak
parent 0dede1ba7d
commit 74d6736afc
14 changed files with 387 additions and 326 deletions

View File

@ -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) {

View File

@ -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());

View File

@ -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());

View File

@ -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);

View File

@ -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 {

View File

@ -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;

View File

@ -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 {

View File

@ -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);

View File

@ -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);
}
} }

View File

@ -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);
}
} }
} }

View File

@ -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);
} }
}; };

View File

@ -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 {

View File

@ -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;
} }
} }

View File

@ -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);
} }
} }
} }