Timeline refactor (#2175)
* Move Timeline files into their own package * Introduce TimelineViewModel, add coroutines * Simplify StatusViewData * Handle timeilne fetch errors * Rework filters, fix ViewThreadFragment * Fix NotificationsFragment * Simplify Notifications and Thread, handle pin * Redo loading in TimelineViewModel * Improve error handling in TimelineViewModel * Rewrite actions in TimelineViewModel * Apply feedback after timeline factoring review * Handle initial failure in timeline correctly
This commit is contained in:
parent
0a992480c2
commit
44a5b42cac
58 changed files with 3956 additions and 3618 deletions
|
|
@ -43,6 +43,7 @@ import com.keylesspalace.tusky.databinding.ItemFollowRequestBinding;
|
|||
import com.keylesspalace.tusky.entity.Account;
|
||||
import com.keylesspalace.tusky.entity.Emoji;
|
||||
import com.keylesspalace.tusky.entity.Notification;
|
||||
import com.keylesspalace.tusky.entity.Status;
|
||||
import com.keylesspalace.tusky.interfaces.AccountActionListener;
|
||||
import com.keylesspalace.tusky.interfaces.LinkListener;
|
||||
import com.keylesspalace.tusky.interfaces.StatusActionListener;
|
||||
|
|
@ -195,14 +196,15 @@ public class NotificationsAdapter extends RecyclerView.Adapter {
|
|||
} else {
|
||||
holder.showNotificationContent(true);
|
||||
|
||||
holder.setDisplayName(statusViewData.getUserFullName(), statusViewData.getAccountEmojis());
|
||||
holder.setUsername(statusViewData.getNickname());
|
||||
holder.setCreatedAt(statusViewData.getCreatedAt());
|
||||
Status status = statusViewData.getActionable();
|
||||
holder.setDisplayName(status.getAccount().getDisplayName(), status.getAccount().getEmojis());
|
||||
holder.setUsername(status.getAccount().getUsername());
|
||||
holder.setCreatedAt(status.getCreatedAt());
|
||||
|
||||
if(concreteNotificaton.getType() == Notification.Type.STATUS) {
|
||||
holder.setAvatar(statusViewData.getAvatar(), statusViewData.isBot());
|
||||
if (concreteNotificaton.getType() == Notification.Type.STATUS) {
|
||||
holder.setAvatar(status.getAccount().getAvatar(), status.getAccount().getBot());
|
||||
} else {
|
||||
holder.setAvatars(statusViewData.getAvatar(),
|
||||
holder.setAvatars(status.getAccount().getAvatar(),
|
||||
concreteNotificaton.getAccount().getAvatar());
|
||||
}
|
||||
}
|
||||
|
|
@ -215,7 +217,7 @@ public class NotificationsAdapter extends RecyclerView.Adapter {
|
|||
if (payloadForHolder instanceof List)
|
||||
for (Object item : (List) payloadForHolder) {
|
||||
if (StatusBaseViewHolder.Key.KEY_CREATED.equals(item) && statusViewData != null) {
|
||||
holder.setCreatedAt(statusViewData.getCreatedAt());
|
||||
holder.setCreatedAt(statusViewData.getStatus().getActionableStatus().getCreatedAt());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -386,7 +388,7 @@ public class NotificationsAdapter extends RecyclerView.Adapter {
|
|||
private StatusViewData.Concrete statusViewData;
|
||||
private SimpleDateFormat shortSdf;
|
||||
private SimpleDateFormat longSdf;
|
||||
|
||||
|
||||
private int avatarRadius48dp;
|
||||
private int avatarRadius36dp;
|
||||
private int avatarRadius24dp;
|
||||
|
|
@ -415,7 +417,7 @@ public class NotificationsAdapter extends RecyclerView.Adapter {
|
|||
statusContent.setOnClickListener(this);
|
||||
shortSdf = new SimpleDateFormat("HH:mm:ss", Locale.getDefault());
|
||||
longSdf = new SimpleDateFormat("MM/dd HH:mm:ss", Locale.getDefault());
|
||||
|
||||
|
||||
this.avatarRadius48dp = itemView.getContext().getResources().getDimensionPixelSize(R.dimen.avatar_radius_48dp);
|
||||
this.avatarRadius36dp = itemView.getContext().getResources().getDimensionPixelSize(R.dimen.avatar_radius_36dp);
|
||||
this.avatarRadius24dp = itemView.getContext().getResources().getDimensionPixelSize(R.dimen.avatar_radius_24dp);
|
||||
|
|
@ -531,7 +533,7 @@ public class NotificationsAdapter extends RecyclerView.Adapter {
|
|||
message.setText(emojifiedText);
|
||||
|
||||
if (statusViewData != null) {
|
||||
boolean hasSpoiler = !TextUtils.isEmpty(statusViewData.getSpoilerText());
|
||||
boolean hasSpoiler = !TextUtils.isEmpty(statusViewData.getStatus().getSpoilerText());
|
||||
contentWarningDescriptionTextView.setVisibility(hasSpoiler ? View.VISIBLE : View.GONE);
|
||||
contentWarningButton.setVisibility(hasSpoiler ? View.VISIBLE : View.GONE);
|
||||
if (statusViewData.isExpanded()) {
|
||||
|
|
@ -586,7 +588,7 @@ public class NotificationsAdapter extends RecyclerView.Adapter {
|
|||
|
||||
notificationAvatar.setVisibility(View.VISIBLE);
|
||||
ImageLoadingHelper.loadAvatar(notificationAvatarUrl, notificationAvatar,
|
||||
avatarRadius24dp, statusDisplayOptions.animateAvatars());
|
||||
avatarRadius24dp, statusDisplayOptions.animateAvatars());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -607,7 +609,7 @@ public class NotificationsAdapter extends RecyclerView.Adapter {
|
|||
private void setupContentAndSpoiler(final LinkListener listener) {
|
||||
|
||||
boolean shouldShowContentIfSpoiler = statusViewData.isExpanded();
|
||||
boolean hasSpoiler = !TextUtils.isEmpty(statusViewData.getSpoilerText());
|
||||
boolean hasSpoiler = !TextUtils.isEmpty(statusViewData.getStatus(). getSpoilerText());
|
||||
if (!shouldShowContentIfSpoiler && hasSpoiler) {
|
||||
statusContent.setVisibility(View.GONE);
|
||||
} else {
|
||||
|
|
@ -615,7 +617,7 @@ public class NotificationsAdapter extends RecyclerView.Adapter {
|
|||
}
|
||||
|
||||
Spanned content = statusViewData.getContent();
|
||||
List<Emoji> emojis = statusViewData.getStatusEmojis();
|
||||
List<Emoji> emojis = statusViewData.getActionable().getEmojis();
|
||||
|
||||
if (statusViewData.isCollapsible() && (statusViewData.isExpanded() || !hasSpoiler)) {
|
||||
contentCollapseButton.setOnClickListener(view -> {
|
||||
|
|
@ -641,13 +643,13 @@ public class NotificationsAdapter extends RecyclerView.Adapter {
|
|||
CharSequence emojifiedText = CustomEmojiHelper.emojify(
|
||||
content, emojis, statusContent, statusDisplayOptions.animateEmojis()
|
||||
);
|
||||
LinkHelper.setClickableText(statusContent, emojifiedText, statusViewData.getMentions(), listener);
|
||||
LinkHelper.setClickableText(statusContent, emojifiedText, statusViewData.getActionable().getMentions(), listener);
|
||||
|
||||
CharSequence emojifiedContentWarning;
|
||||
if (statusViewData.getSpoilerText() != null) {
|
||||
emojifiedContentWarning = CustomEmojiHelper.emojify(
|
||||
statusViewData.getSpoilerText(),
|
||||
statusViewData.getStatusEmojis(),
|
||||
statusViewData.getActionable().getEmojis(),
|
||||
contentWarningDescriptionTextView,
|
||||
statusDisplayOptions.animateEmojis()
|
||||
);
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ public final class PlaceholderViewHolder extends RecyclerView.ViewHolder {
|
|||
private Button loadMoreButton;
|
||||
private ProgressBar progressBar;
|
||||
|
||||
PlaceholderViewHolder(View itemView) {
|
||||
public PlaceholderViewHolder(View itemView) {
|
||||
super(itemView);
|
||||
loadMoreButton = itemView.findViewById(R.id.button_load_more);
|
||||
progressBar = itemView.findViewById(R.id.progressBar);
|
||||
|
|
|
|||
|
|
@ -201,7 +201,7 @@ public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder {
|
|||
protected void setSpoilerAndContent(boolean expanded,
|
||||
@NonNull Spanned content,
|
||||
@Nullable String spoilerText,
|
||||
@Nullable Status.Mention[] mentions,
|
||||
@Nullable List<Status.Mention> mentions,
|
||||
@NonNull List<Emoji> emojis,
|
||||
@Nullable PollViewData poll,
|
||||
@NonNull StatusDisplayOptions statusDisplayOptions,
|
||||
|
|
@ -243,7 +243,7 @@ public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder {
|
|||
private void setTextVisible(boolean sensitive,
|
||||
boolean expanded,
|
||||
Spanned content,
|
||||
Status.Mention[] mentions,
|
||||
List<Status.Mention> mentions,
|
||||
List<Emoji> emojis,
|
||||
@Nullable PollViewData poll,
|
||||
StatusDisplayOptions statusDisplayOptions,
|
||||
|
|
@ -708,21 +708,23 @@ public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder {
|
|||
this.setupWithStatus(status, listener, statusDisplayOptions, null);
|
||||
}
|
||||
|
||||
protected void setupWithStatus(StatusViewData.Concrete status,
|
||||
final StatusActionListener listener,
|
||||
StatusDisplayOptions statusDisplayOptions,
|
||||
@Nullable Object payloads) {
|
||||
public void setupWithStatus(StatusViewData.Concrete status,
|
||||
final StatusActionListener listener,
|
||||
StatusDisplayOptions statusDisplayOptions,
|
||||
@Nullable Object payloads) {
|
||||
if (payloads == null) {
|
||||
setDisplayName(status.getUserFullName(), status.getAccountEmojis(), statusDisplayOptions);
|
||||
setUsername(status.getNickname());
|
||||
setCreatedAt(status.getCreatedAt(), statusDisplayOptions);
|
||||
setIsReply(status.getInReplyToId() != null);
|
||||
setAvatar(status.getAvatar(), status.getRebloggedAvatar(), status.isBot(), statusDisplayOptions);
|
||||
setReblogged(status.isReblogged());
|
||||
setFavourited(status.isFavourited());
|
||||
setBookmarked(status.isBookmarked());
|
||||
List<Attachment> attachments = status.getAttachments();
|
||||
boolean sensitive = status.isSensitive();
|
||||
Status actionable = status.getActionable();
|
||||
setDisplayName(actionable.getAccount().getDisplayName(), actionable.getAccount().getEmojis(), statusDisplayOptions);
|
||||
setUsername(status.getUsername());
|
||||
setCreatedAt(actionable.getCreatedAt(), statusDisplayOptions);
|
||||
setIsReply(actionable.getInReplyToId() != null);
|
||||
setAvatar(actionable.getAccount().getAvatar(), status.getRebloggedAvatar(),
|
||||
actionable.getAccount().getBot(), statusDisplayOptions);
|
||||
setReblogged(actionable.getReblogged());
|
||||
setFavourited(actionable.getFavourited());
|
||||
setBookmarked(actionable.getBookmarked());
|
||||
List<Attachment> attachments = actionable.getAttachments();
|
||||
boolean sensitive = actionable.getSensitive();
|
||||
if (statusDisplayOptions.mediaPreviewEnabled() && hasPreviewableAttachment(attachments)) {
|
||||
setMediaPreviews(attachments, sensitive, listener, status.isShowingContent(), statusDisplayOptions.useBlurhash());
|
||||
|
||||
|
|
@ -747,11 +749,14 @@ public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder {
|
|||
setupCard(status, statusDisplayOptions.cardViewMode(), statusDisplayOptions);
|
||||
}
|
||||
|
||||
setupButtons(listener, status.getSenderId(), status.getContent().toString(),
|
||||
setupButtons(listener, actionable.getAccount().getId(), status.getContent().toString(),
|
||||
statusDisplayOptions);
|
||||
setRebloggingEnabled(status.getRebloggingEnabled(), status.getVisibility());
|
||||
setRebloggingEnabled(actionable.rebloggingAllowed(), actionable.getVisibility());
|
||||
|
||||
setSpoilerAndContent(status.isExpanded(), status.getContent(), status.getSpoilerText(), status.getMentions(), status.getStatusEmojis(), status.getPoll(), statusDisplayOptions, listener);
|
||||
setSpoilerAndContent(status.isExpanded(), status.getContent(), status.getSpoilerText(),
|
||||
actionable.getMentions(), actionable.getEmojis(),
|
||||
PollViewDataKt.toViewData(actionable.getPoll()), statusDisplayOptions,
|
||||
listener);
|
||||
|
||||
setDescriptionForStatus(status, statusDisplayOptions);
|
||||
|
||||
|
|
@ -765,7 +770,7 @@ public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder {
|
|||
if (payloads instanceof List)
|
||||
for (Object item : (List<?>) payloads) {
|
||||
if (Key.KEY_CREATED.equals(item)) {
|
||||
setCreatedAt(status.getCreatedAt(), statusDisplayOptions);
|
||||
setCreatedAt(status.getActionable().getCreatedAt(), statusDisplayOptions);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -784,21 +789,22 @@ public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder {
|
|||
private void setDescriptionForStatus(@NonNull StatusViewData.Concrete status,
|
||||
StatusDisplayOptions statusDisplayOptions) {
|
||||
Context context = itemView.getContext();
|
||||
Status actionable = status.getActionable();
|
||||
|
||||
String description = context.getString(R.string.description_status,
|
||||
status.getUserFullName(),
|
||||
actionable.getAccount().getDisplayName(),
|
||||
getContentWarningDescription(context, status),
|
||||
(TextUtils.isEmpty(status.getSpoilerText()) || !status.isSensitive() || status.isExpanded() ? status.getContent() : ""),
|
||||
getCreatedAtDescription(status.getCreatedAt(), statusDisplayOptions),
|
||||
(TextUtils.isEmpty(status.getSpoilerText()) || !actionable.getSensitive() || status.isExpanded() ? status.getContent() : ""),
|
||||
getCreatedAtDescription(actionable.getCreatedAt(), statusDisplayOptions),
|
||||
getReblogDescription(context, status),
|
||||
status.getNickname(),
|
||||
status.isReblogged() ? context.getString(R.string.description_status_reblogged) : "",
|
||||
status.isFavourited() ? context.getString(R.string.description_status_favourited) : "",
|
||||
status.isBookmarked() ? context.getString(R.string.description_status_bookmarked) : "",
|
||||
status.getUsername(),
|
||||
actionable.getReblogged() ? context.getString(R.string.description_status_reblogged) : "",
|
||||
actionable.getFavourited() ? context.getString(R.string.description_status_favourited) : "",
|
||||
actionable.getBookmarked() ? context.getString(R.string.description_status_bookmarked) : "",
|
||||
getMediaDescription(context, status),
|
||||
getVisibilityDescription(context, status.getVisibility()),
|
||||
getFavsText(context, status.getFavouritesCount()),
|
||||
getReblogsText(context, status.getReblogsCount()),
|
||||
getVisibilityDescription(context, actionable.getVisibility()),
|
||||
getFavsText(context, actionable.getFavouritesCount()),
|
||||
getReblogsText(context, actionable.getReblogsCount()),
|
||||
getPollDescription(status, context, statusDisplayOptions)
|
||||
);
|
||||
itemView.setContentDescription(description);
|
||||
|
|
@ -806,10 +812,10 @@ public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder {
|
|||
|
||||
private static CharSequence getReblogDescription(Context context,
|
||||
@NonNull StatusViewData.Concrete status) {
|
||||
String rebloggedUsername = status.getRebloggedByUsername();
|
||||
if (rebloggedUsername != null) {
|
||||
Status reblog = status.getRebloggingStatus();
|
||||
if (reblog != null) {
|
||||
return context
|
||||
.getString(R.string.status_boosted_format, rebloggedUsername);
|
||||
.getString(R.string.status_boosted_format, reblog.getAccount().getUsername());
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
|
|
@ -817,11 +823,11 @@ public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder {
|
|||
|
||||
private static CharSequence getMediaDescription(Context context,
|
||||
@NonNull StatusViewData.Concrete status) {
|
||||
if (status.getAttachments().isEmpty()) {
|
||||
if (status.getActionable().getAttachments().isEmpty()) {
|
||||
return "";
|
||||
}
|
||||
StringBuilder mediaDescriptions = CollectionsKt.fold(
|
||||
status.getAttachments(),
|
||||
status.getActionable().getAttachments(),
|
||||
new StringBuilder(),
|
||||
(builder, a) -> {
|
||||
if (a.getDescription() == null) {
|
||||
|
|
@ -874,7 +880,7 @@ public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder {
|
|||
private CharSequence getPollDescription(@NonNull StatusViewData.Concrete status,
|
||||
Context context,
|
||||
StatusDisplayOptions statusDisplayOptions) {
|
||||
PollViewData poll = status.getPoll();
|
||||
PollViewData poll = PollViewDataKt.toViewData(status.getActionable().getPoll());
|
||||
if (poll == null) {
|
||||
return "";
|
||||
} else {
|
||||
|
|
@ -980,7 +986,7 @@ public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder {
|
|||
StatusDisplayOptions statusDisplayOptions,
|
||||
Context context) {
|
||||
String votesText;
|
||||
if(poll.getVotersCount() == null) {
|
||||
if (poll.getVotersCount() == null) {
|
||||
String voters = numberFormat.format(poll.getVotesCount());
|
||||
votesText = context.getResources().getQuantityString(R.plurals.poll_info_votes, poll.getVotesCount(), voters);
|
||||
} else {
|
||||
|
|
@ -1004,12 +1010,12 @@ public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder {
|
|||
}
|
||||
|
||||
protected void setupCard(StatusViewData.Concrete status, CardViewMode cardViewMode, StatusDisplayOptions statusDisplayOptions) {
|
||||
final Card card = status.getActionable().getCard();
|
||||
if (cardViewMode != CardViewMode.NONE &&
|
||||
status.getAttachments().size() == 0 &&
|
||||
status.getCard() != null &&
|
||||
!TextUtils.isEmpty(status.getCard().getUrl()) &&
|
||||
status.getActionable().getAttachments().size() == 0 &&
|
||||
card != null &&
|
||||
!TextUtils.isEmpty(card.getUrl()) &&
|
||||
(!status.isCollapsible() || !status.isCollapsed())) {
|
||||
final Card card = status.getCard();
|
||||
cardView.setVisibility(View.VISIBLE);
|
||||
cardTitle.setText(card.getTitle());
|
||||
if (TextUtils.isEmpty(card.getDescription()) && TextUtils.isEmpty(card.getAuthorName())) {
|
||||
|
|
@ -1028,7 +1034,7 @@ public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder {
|
|||
// Statuses from other activitypub sources can be marked sensitive even if there's no media,
|
||||
// so let's blur the preview in that case
|
||||
// If media previews are disabled, show placeholder for cards as well
|
||||
if (statusDisplayOptions.mediaPreviewEnabled() && !status.isSensitive() && !TextUtils.isEmpty(card.getImage())) {
|
||||
if (statusDisplayOptions.mediaPreviewEnabled() && !status.getActionable().getSensitive() && !TextUtils.isEmpty(card.getImage())) {
|
||||
|
||||
int topLeftRadius = 0;
|
||||
int topRightRadius = 0;
|
||||
|
|
|
|||
|
|
@ -101,7 +101,7 @@ class StatusDetailedViewHolder extends StatusBaseViewHolder {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected void setupWithStatus(final StatusViewData.Concrete status,
|
||||
public void setupWithStatus(final StatusViewData.Concrete status,
|
||||
final StatusActionListener listener,
|
||||
StatusDisplayOptions statusDisplayOptions,
|
||||
@Nullable Object payloads) {
|
||||
|
|
@ -110,12 +110,13 @@ class StatusDetailedViewHolder extends StatusBaseViewHolder {
|
|||
if (payloads == null) {
|
||||
|
||||
if (!statusDisplayOptions.hideStats()) {
|
||||
setReblogAndFavCount(status.getReblogsCount(), status.getFavouritesCount(), listener);
|
||||
setReblogAndFavCount(status.getActionable().getReblogsCount(),
|
||||
status.getActionable().getFavouritesCount(), listener);
|
||||
} else {
|
||||
hideQuantitativeStats();
|
||||
}
|
||||
|
||||
setApplication(status.getApplication());
|
||||
setApplication(status.getActionable().getApplication());
|
||||
|
||||
View.OnLongClickListener longClickListener = view -> {
|
||||
TextView textView = (TextView) view;
|
||||
|
|
@ -130,7 +131,7 @@ class StatusDetailedViewHolder extends StatusBaseViewHolder {
|
|||
|
||||
content.setOnLongClickListener(longClickListener);
|
||||
contentWarningDescription.setOnLongClickListener(longClickListener);
|
||||
setStatusVisibility(status.getVisibility());
|
||||
setStatusVisibility(status.getActionable().getVisibility());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -26,6 +26,8 @@ import androidx.annotation.Nullable;
|
|||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.keylesspalace.tusky.R;
|
||||
import com.keylesspalace.tusky.entity.Emoji;
|
||||
import com.keylesspalace.tusky.entity.Status;
|
||||
import com.keylesspalace.tusky.interfaces.StatusActionListener;
|
||||
import com.keylesspalace.tusky.util.CustomEmojiHelper;
|
||||
import com.keylesspalace.tusky.util.SmartLengthInputFilter;
|
||||
|
|
@ -33,6 +35,8 @@ import com.keylesspalace.tusky.util.StatusDisplayOptions;
|
|||
import com.keylesspalace.tusky.util.StringUtils;
|
||||
import com.keylesspalace.tusky.viewdata.StatusViewData;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import at.connyduck.sparkbutton.helpers.Utils;
|
||||
|
||||
public class StatusViewHolder extends StatusBaseViewHolder {
|
||||
|
|
@ -54,19 +58,21 @@ public class StatusViewHolder extends StatusBaseViewHolder {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected void setupWithStatus(StatusViewData.Concrete status,
|
||||
final StatusActionListener listener,
|
||||
StatusDisplayOptions statusDisplayOptions,
|
||||
@Nullable Object payloads) {
|
||||
public void setupWithStatus(StatusViewData.Concrete status,
|
||||
final StatusActionListener listener,
|
||||
StatusDisplayOptions statusDisplayOptions,
|
||||
@Nullable Object payloads) {
|
||||
if (payloads == null) {
|
||||
|
||||
setupCollapsedState(status, listener);
|
||||
|
||||
String rebloggedByDisplayName = status.getRebloggedByUsername();
|
||||
if (rebloggedByDisplayName == null) {
|
||||
Status reblogging = status.getRebloggingStatus();
|
||||
if (reblogging == null) {
|
||||
hideStatusInfo();
|
||||
} else {
|
||||
setRebloggedByDisplayName(rebloggedByDisplayName, status, statusDisplayOptions);
|
||||
String rebloggedByDisplayName = reblogging.getAccount().getDisplayName();
|
||||
setRebloggedByDisplayName(rebloggedByDisplayName,
|
||||
reblogging.getAccount().getEmojis(), statusDisplayOptions);
|
||||
statusInfo.setOnClickListener(v -> listener.onOpenReblog(getBindingAdapterPosition()));
|
||||
}
|
||||
|
||||
|
|
@ -76,13 +82,13 @@ public class StatusViewHolder extends StatusBaseViewHolder {
|
|||
}
|
||||
|
||||
private void setRebloggedByDisplayName(final CharSequence name,
|
||||
final StatusViewData.Concrete status,
|
||||
final List<Emoji> accountEmoji,
|
||||
final StatusDisplayOptions statusDisplayOptions) {
|
||||
Context context = statusInfo.getContext();
|
||||
CharSequence wrappedName = StringUtils.unicodeWrap(name);
|
||||
CharSequence boostedText = context.getString(R.string.status_boosted_format, wrappedName);
|
||||
CharSequence emojifiedText = CustomEmojiHelper.emojify(
|
||||
boostedText, status.getRebloggedByAccountEmojis(), statusInfo, statusDisplayOptions.animateEmojis()
|
||||
boostedText, accountEmoji, statusInfo, statusDisplayOptions.animateEmojis()
|
||||
);
|
||||
statusInfo.setText(emojifiedText);
|
||||
statusInfo.setVisibility(View.VISIBLE);
|
||||
|
|
|
|||
|
|
@ -1,135 +0,0 @@
|
|||
/* Copyright 2017 Andrew Dawson
|
||||
*
|
||||
* This file is a part of Tusky.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under the terms of the
|
||||
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* Tusky is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
||||
* Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with Tusky; if not,
|
||||
* see <http://www.gnu.org/licenses>. */
|
||||
|
||||
package com.keylesspalace.tusky.adapter;
|
||||
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.keylesspalace.tusky.R;
|
||||
import com.keylesspalace.tusky.interfaces.StatusActionListener;
|
||||
import com.keylesspalace.tusky.util.StatusDisplayOptions;
|
||||
import com.keylesspalace.tusky.viewdata.StatusViewData;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public final class TimelineAdapter extends RecyclerView.Adapter {
|
||||
|
||||
public interface AdapterDataSource<T> {
|
||||
int getItemCount();
|
||||
|
||||
T getItemAt(int pos);
|
||||
}
|
||||
|
||||
private static final int VIEW_TYPE_STATUS = 0;
|
||||
private static final int VIEW_TYPE_PLACEHOLDER = 2;
|
||||
|
||||
private final AdapterDataSource<StatusViewData> dataSource;
|
||||
private StatusDisplayOptions statusDisplayOptions;
|
||||
private final StatusActionListener statusListener;
|
||||
|
||||
public TimelineAdapter(AdapterDataSource<StatusViewData> dataSource,
|
||||
StatusDisplayOptions statusDisplayOptions,
|
||||
StatusActionListener statusListener) {
|
||||
this.dataSource = dataSource;
|
||||
this.statusDisplayOptions = statusDisplayOptions;
|
||||
this.statusListener = statusListener;
|
||||
}
|
||||
|
||||
public boolean getMediaPreviewEnabled() {
|
||||
return statusDisplayOptions.mediaPreviewEnabled();
|
||||
}
|
||||
|
||||
public void setMediaPreviewEnabled(boolean mediaPreviewEnabled) {
|
||||
this.statusDisplayOptions = statusDisplayOptions.copy(
|
||||
statusDisplayOptions.animateAvatars(),
|
||||
mediaPreviewEnabled,
|
||||
statusDisplayOptions.useAbsoluteTime(),
|
||||
statusDisplayOptions.showBotOverlay(),
|
||||
statusDisplayOptions.useBlurhash(),
|
||||
statusDisplayOptions.cardViewMode(),
|
||||
statusDisplayOptions.confirmReblogs(),
|
||||
statusDisplayOptions.hideStats(),
|
||||
statusDisplayOptions.animateEmojis()
|
||||
);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int viewType) {
|
||||
switch (viewType) {
|
||||
default:
|
||||
case VIEW_TYPE_STATUS: {
|
||||
View view = LayoutInflater.from(viewGroup.getContext())
|
||||
.inflate(R.layout.item_status, viewGroup, false);
|
||||
return new StatusViewHolder(view);
|
||||
}
|
||||
case VIEW_TYPE_PLACEHOLDER: {
|
||||
View view = LayoutInflater.from(viewGroup.getContext())
|
||||
.inflate(R.layout.item_status_placeholder, viewGroup, false);
|
||||
return new PlaceholderViewHolder(view);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, int position) {
|
||||
bindViewHolder(viewHolder, position, null);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, int position, @NonNull List payloads) {
|
||||
bindViewHolder(viewHolder, position, payloads);
|
||||
}
|
||||
|
||||
private void bindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, int position, @Nullable List payloads) {
|
||||
StatusViewData status = dataSource.getItemAt(position);
|
||||
if (status instanceof StatusViewData.Placeholder) {
|
||||
PlaceholderViewHolder holder = (PlaceholderViewHolder) viewHolder;
|
||||
holder.setup(statusListener, ((StatusViewData.Placeholder) status).isLoading());
|
||||
} else if (status instanceof StatusViewData.Concrete) {
|
||||
StatusViewHolder holder = (StatusViewHolder) viewHolder;
|
||||
holder.setupWithStatus((StatusViewData.Concrete) status,
|
||||
statusListener,
|
||||
statusDisplayOptions,
|
||||
payloads != null && !payloads.isEmpty() ? payloads.get(0) : null);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return dataSource.getItemCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemViewType(int position) {
|
||||
if (dataSource.getItemAt(position) instanceof StatusViewData.Placeholder) {
|
||||
return VIEW_TYPE_PLACEHOLDER;
|
||||
} else {
|
||||
return VIEW_TYPE_STATUS;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getItemId(int position) {
|
||||
return dataSource.getItemAt(position).getViewDataId();
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue