* Use blurhash as image preview and as sensitive media cover, close #1571 * Fix focal point for blurhashes * Fix video indicator overlapping sensitive media indicator * Add a preference for blurhash * Add blurhash to report UI. * Introduce StatusDisplayOptions
This commit is contained in:
parent
2994af7091
commit
7623962a0d
32 changed files with 560 additions and 368 deletions
|
@ -33,6 +33,12 @@ import android.widget.ImageView;
|
|||
import android.widget.TextView;
|
||||
import android.widget.ToggleButton;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.core.text.BidiFormatter;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.keylesspalace.tusky.R;
|
||||
import com.keylesspalace.tusky.entity.Account;
|
||||
import com.keylesspalace.tusky.entity.Emoji;
|
||||
|
@ -40,10 +46,11 @@ import com.keylesspalace.tusky.entity.Notification;
|
|||
import com.keylesspalace.tusky.interfaces.LinkListener;
|
||||
import com.keylesspalace.tusky.interfaces.StatusActionListener;
|
||||
import com.keylesspalace.tusky.util.CustomEmojiHelper;
|
||||
import com.keylesspalace.tusky.util.TimestampUtils;
|
||||
import com.keylesspalace.tusky.util.ImageLoadingHelper;
|
||||
import com.keylesspalace.tusky.util.LinkHelper;
|
||||
import com.keylesspalace.tusky.util.SmartLengthInputFilter;
|
||||
import com.keylesspalace.tusky.util.StatusDisplayOptions;
|
||||
import com.keylesspalace.tusky.util.TimestampUtils;
|
||||
import com.keylesspalace.tusky.viewdata.NotificationViewData;
|
||||
import com.keylesspalace.tusky.viewdata.StatusViewData;
|
||||
import com.mikepenz.iconics.utils.Utils;
|
||||
|
@ -53,12 +60,6 @@ import java.util.Date;
|
|||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.core.text.BidiFormatter;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
public class NotificationsAdapter extends RecyclerView.Adapter {
|
||||
|
||||
public interface AdapterDataSource<T> {
|
||||
|
@ -78,28 +79,23 @@ public class NotificationsAdapter extends RecyclerView.Adapter {
|
|||
private static final InputFilter[] NO_INPUT_FILTER = new InputFilter[0];
|
||||
|
||||
private String accountId;
|
||||
private StatusDisplayOptions statusDisplayOptions;
|
||||
private StatusActionListener statusListener;
|
||||
private NotificationActionListener notificationActionListener;
|
||||
private boolean mediaPreviewEnabled;
|
||||
private boolean useAbsoluteTime;
|
||||
private boolean showBotOverlay;
|
||||
private boolean animateAvatar;
|
||||
private BidiFormatter bidiFormatter;
|
||||
private AdapterDataSource<NotificationViewData> dataSource;
|
||||
|
||||
public NotificationsAdapter(String accountId,
|
||||
AdapterDataSource<NotificationViewData> dataSource,
|
||||
StatusDisplayOptions statusDisplayOptions,
|
||||
StatusActionListener statusListener,
|
||||
NotificationActionListener notificationActionListener) {
|
||||
|
||||
this.accountId = accountId;
|
||||
this.dataSource = dataSource;
|
||||
this.statusDisplayOptions = statusDisplayOptions;
|
||||
this.statusListener = statusListener;
|
||||
this.notificationActionListener = notificationActionListener;
|
||||
mediaPreviewEnabled = true;
|
||||
useAbsoluteTime = false;
|
||||
showBotOverlay = true;
|
||||
animateAvatar = false;
|
||||
bidiFormatter = BidiFormatter.getInstance();
|
||||
}
|
||||
|
||||
|
@ -108,20 +104,20 @@ public class NotificationsAdapter extends RecyclerView.Adapter {
|
|||
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
|
||||
switch (viewType) {
|
||||
case VIEW_TYPE_STATUS: {
|
||||
case VIEW_TYPE_STATUS: {
|
||||
View view = inflater
|
||||
.inflate(R.layout.item_status, parent, false);
|
||||
return new StatusViewHolder(view, useAbsoluteTime);
|
||||
return new StatusViewHolder(view);
|
||||
}
|
||||
case VIEW_TYPE_STATUS_NOTIFICATION: {
|
||||
View view = inflater
|
||||
.inflate(R.layout.item_status_notification, parent, false);
|
||||
return new StatusNotificationViewHolder(view, useAbsoluteTime, animateAvatar);
|
||||
return new StatusNotificationViewHolder(view, statusDisplayOptions);
|
||||
}
|
||||
case VIEW_TYPE_FOLLOW: {
|
||||
View view = inflater
|
||||
.inflate(R.layout.item_follow, parent, false);
|
||||
return new FollowViewHolder(view, animateAvatar);
|
||||
return new FollowViewHolder(view, statusDisplayOptions);
|
||||
}
|
||||
case VIEW_TYPE_PLACEHOLDER: {
|
||||
View view = inflater
|
||||
|
@ -137,7 +133,8 @@ public class NotificationsAdapter extends RecyclerView.Adapter {
|
|||
Utils.convertDpToPx(parent.getContext(), 24)
|
||||
)
|
||||
);
|
||||
return new RecyclerView.ViewHolder(view) {};
|
||||
return new RecyclerView.ViewHolder(view) {
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -171,8 +168,8 @@ public class NotificationsAdapter extends RecyclerView.Adapter {
|
|||
StatusViewHolder holder = (StatusViewHolder) viewHolder;
|
||||
StatusViewData.Concrete status = concreteNotificaton.getStatusViewData();
|
||||
holder.setupWithStatus(status,
|
||||
statusListener, mediaPreviewEnabled, showBotOverlay, animateAvatar, payloadForHolder);
|
||||
if(concreteNotificaton.getType() == Notification.Type.POLL) {
|
||||
statusListener, statusDisplayOptions, payloadForHolder);
|
||||
if (concreteNotificaton.getType() == Notification.Type.POLL) {
|
||||
holder.setPollInfo(accountId.equals(concreteNotificaton.getAccount().getId()));
|
||||
} else {
|
||||
holder.hideStatusInfo();
|
||||
|
@ -202,7 +199,7 @@ public class NotificationsAdapter extends RecyclerView.Adapter {
|
|||
concreteNotificaton.getId());
|
||||
} else {
|
||||
if (payloadForHolder instanceof List)
|
||||
for (Object item : (List)payloadForHolder) {
|
||||
for (Object item : (List) payloadForHolder) {
|
||||
if (StatusBaseViewHolder.Key.KEY_CREATED.equals(item)) {
|
||||
holder.setCreatedAt(statusViewData.getCreatedAt());
|
||||
}
|
||||
|
@ -221,7 +218,6 @@ public class NotificationsAdapter extends RecyclerView.Adapter {
|
|||
default:
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -229,6 +225,20 @@ public class NotificationsAdapter extends RecyclerView.Adapter {
|
|||
return dataSource.getItemCount();
|
||||
}
|
||||
|
||||
public void setMediaPreviewEnabled(boolean mediaPreviewEnabled) {
|
||||
this.statusDisplayOptions = statusDisplayOptions.copy(
|
||||
statusDisplayOptions.animateAvatars(),
|
||||
mediaPreviewEnabled,
|
||||
statusDisplayOptions.useAbsoluteTime(),
|
||||
statusDisplayOptions.showBotOverlay(),
|
||||
statusDisplayOptions.useBlurhash()
|
||||
);
|
||||
}
|
||||
|
||||
public boolean isMediaPreviewEnabled() {
|
||||
return this.statusDisplayOptions.mediaPreviewEnabled();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemViewType(int position) {
|
||||
NotificationViewData notification = dataSource.getItemAt(position);
|
||||
|
@ -256,26 +266,7 @@ public class NotificationsAdapter extends RecyclerView.Adapter {
|
|||
throw new AssertionError("Unknown notification type");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void setMediaPreviewEnabled(boolean enabled) {
|
||||
mediaPreviewEnabled = enabled;
|
||||
}
|
||||
|
||||
public boolean isMediaPreviewEnabled() {
|
||||
return mediaPreviewEnabled;
|
||||
}
|
||||
|
||||
public void setUseAbsoluteTime(boolean useAbsoluteTime) {
|
||||
this.useAbsoluteTime = useAbsoluteTime;
|
||||
}
|
||||
|
||||
public void setShowBotOverlay(boolean showBotOverlay) {
|
||||
this.showBotOverlay = showBotOverlay;
|
||||
}
|
||||
|
||||
public void setAnimateAvatar(boolean animateAvatar) {
|
||||
this.animateAvatar = animateAvatar;
|
||||
}
|
||||
|
||||
public interface NotificationActionListener {
|
||||
|
@ -300,15 +291,15 @@ public class NotificationsAdapter extends RecyclerView.Adapter {
|
|||
private TextView usernameView;
|
||||
private TextView displayNameView;
|
||||
private ImageView avatar;
|
||||
private boolean animateAvatar;
|
||||
private StatusDisplayOptions statusDisplayOptions;
|
||||
|
||||
FollowViewHolder(View itemView, boolean animateAvatar) {
|
||||
FollowViewHolder(View itemView, StatusDisplayOptions statusDisplayOptions) {
|
||||
super(itemView);
|
||||
message = itemView.findViewById(R.id.notification_text);
|
||||
usernameView = itemView.findViewById(R.id.notification_username);
|
||||
displayNameView = itemView.findViewById(R.id.notification_display_name);
|
||||
avatar = itemView.findViewById(R.id.notification_avatar);
|
||||
this.animateAvatar = animateAvatar;
|
||||
this.statusDisplayOptions = statusDisplayOptions;
|
||||
}
|
||||
|
||||
void setMessage(Account account, BidiFormatter bidiFormatter) {
|
||||
|
@ -330,7 +321,8 @@ public class NotificationsAdapter extends RecyclerView.Adapter {
|
|||
int avatarRadius = avatar.getContext().getResources()
|
||||
.getDimensionPixelSize(R.dimen.avatar_radius_42dp);
|
||||
|
||||
ImageLoadingHelper.loadAvatar(account.getAvatar(), avatar, avatarRadius, animateAvatar);
|
||||
ImageLoadingHelper.loadAvatar(account.getAvatar(), avatar, avatarRadius,
|
||||
statusDisplayOptions.animateAvatars());
|
||||
|
||||
}
|
||||
|
||||
|
@ -352,18 +344,16 @@ public class NotificationsAdapter extends RecyclerView.Adapter {
|
|||
private final TextView contentWarningDescriptionTextView;
|
||||
private final ToggleButton contentWarningButton;
|
||||
private final ToggleButton contentCollapseButton; // TODO: This code SHOULD be based on StatusBaseViewHolder
|
||||
private StatusDisplayOptions statusDisplayOptions;
|
||||
|
||||
private String accountId;
|
||||
private String notificationId;
|
||||
private NotificationActionListener notificationActionListener;
|
||||
private StatusViewData.Concrete statusViewData;
|
||||
|
||||
private boolean useAbsoluteTime;
|
||||
private boolean animateAvatar;
|
||||
private SimpleDateFormat shortSdf;
|
||||
private SimpleDateFormat longSdf;
|
||||
|
||||
StatusNotificationViewHolder(View itemView, boolean useAbsoluteTime, boolean animateAvatar) {
|
||||
StatusNotificationViewHolder(View itemView, StatusDisplayOptions statusDisplayOptions) {
|
||||
super(itemView);
|
||||
message = itemView.findViewById(R.id.notification_top_text);
|
||||
statusNameBar = itemView.findViewById(R.id.status_name_bar);
|
||||
|
@ -376,6 +366,7 @@ public class NotificationsAdapter extends RecyclerView.Adapter {
|
|||
contentWarningDescriptionTextView = itemView.findViewById(R.id.notification_content_warning_description);
|
||||
contentWarningButton = itemView.findViewById(R.id.notification_content_warning_button);
|
||||
contentCollapseButton = itemView.findViewById(R.id.button_toggle_notification_content);
|
||||
this.statusDisplayOptions = statusDisplayOptions;
|
||||
|
||||
int darkerFilter = Color.rgb(123, 123, 123);
|
||||
statusAvatar.setColorFilter(darkerFilter, PorterDuff.Mode.MULTIPLY);
|
||||
|
@ -385,9 +376,6 @@ public class NotificationsAdapter extends RecyclerView.Adapter {
|
|||
message.setOnClickListener(this);
|
||||
statusContent.setOnClickListener(this);
|
||||
contentWarningButton.setOnCheckedChangeListener(this);
|
||||
|
||||
this.useAbsoluteTime = useAbsoluteTime;
|
||||
this.animateAvatar = animateAvatar;
|
||||
shortSdf = new SimpleDateFormat("HH:mm:ss", Locale.getDefault());
|
||||
longSdf = new SimpleDateFormat("MM/dd HH:mm:ss", Locale.getDefault());
|
||||
}
|
||||
|
@ -414,7 +402,7 @@ public class NotificationsAdapter extends RecyclerView.Adapter {
|
|||
}
|
||||
|
||||
protected void setCreatedAt(@Nullable Date createdAt) {
|
||||
if (useAbsoluteTime) {
|
||||
if (statusDisplayOptions.useAbsoluteTime()) {
|
||||
String time;
|
||||
if (createdAt != null) {
|
||||
if (System.currentTimeMillis() - createdAt.getTime() > 86400000L) {
|
||||
|
@ -511,13 +499,13 @@ public class NotificationsAdapter extends RecyclerView.Adapter {
|
|||
.getDimensionPixelSize(R.dimen.avatar_radius_36dp);
|
||||
|
||||
ImageLoadingHelper.loadAvatar(statusAvatarUrl,
|
||||
statusAvatar, statusAvatarRadius, animateAvatar);
|
||||
statusAvatar, statusAvatarRadius, statusDisplayOptions.animateAvatars());
|
||||
|
||||
int notificationAvatarRadius = statusAvatar.getContext().getResources()
|
||||
.getDimensionPixelSize(R.dimen.avatar_radius_24dp);
|
||||
|
||||
ImageLoadingHelper.loadAvatar(notificationAvatarUrl,
|
||||
notificationAvatar, notificationAvatarRadius, animateAvatar);
|
||||
ImageLoadingHelper.loadAvatar(notificationAvatarUrl, notificationAvatar,
|
||||
notificationAvatarRadius, statusDisplayOptions.animateAvatars());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
package com.keylesspalace.tusky.adapter;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.drawable.BitmapDrawable;
|
||||
import android.graphics.drawable.ColorDrawable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.text.Spanned;
|
||||
import android.text.TextUtils;
|
||||
|
@ -32,6 +34,7 @@ import com.keylesspalace.tusky.util.CustomEmojiHelper;
|
|||
import com.keylesspalace.tusky.util.HtmlUtils;
|
||||
import com.keylesspalace.tusky.util.ImageLoadingHelper;
|
||||
import com.keylesspalace.tusky.util.LinkHelper;
|
||||
import com.keylesspalace.tusky.util.StatusDisplayOptions;
|
||||
import com.keylesspalace.tusky.util.ThemeUtils;
|
||||
import com.keylesspalace.tusky.util.TimestampUtils;
|
||||
import com.keylesspalace.tusky.view.MediaPreviewImageView;
|
||||
|
@ -49,7 +52,6 @@ import java.util.Locale;
|
|||
import java.util.Objects;
|
||||
|
||||
import at.connyduck.sparkbutton.SparkButton;
|
||||
import at.connyduck.sparkbutton.SparkEventListener;
|
||||
import kotlin.collections.CollectionsKt;
|
||||
|
||||
import static com.keylesspalace.tusky.viewdata.PollViewDataKt.buildDescription;
|
||||
|
@ -95,10 +97,9 @@ public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder {
|
|||
private int avatarRadius36dp;
|
||||
private int avatarRadius24dp;
|
||||
|
||||
private final int mediaPreviewUnloadedId;
|
||||
private final Drawable mediaPreviewUnloaded;
|
||||
|
||||
protected StatusBaseViewHolder(View itemView,
|
||||
boolean useAbsoluteTime) {
|
||||
protected StatusBaseViewHolder(View itemView) {
|
||||
super(itemView);
|
||||
displayName = itemView.findViewById(R.id.status_display_name);
|
||||
username = itemView.findViewById(R.id.status_username);
|
||||
|
@ -152,8 +153,10 @@ public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder {
|
|||
this.avatarRadius36dp = itemView.getContext().getResources().getDimensionPixelSize(R.dimen.avatar_radius_36dp);
|
||||
this.avatarRadius24dp = itemView.getContext().getResources().getDimensionPixelSize(R.dimen.avatar_radius_24dp);
|
||||
|
||||
mediaPreviewUnloadedId = ThemeUtils.getDrawableId(itemView.getContext(),
|
||||
R.attr.media_preview_unloaded_drawable, android.R.color.black);
|
||||
mediaPreviewUnloaded = itemView.getContext().getDrawable(
|
||||
ThemeUtils.getDrawableId(itemView.getContext(),
|
||||
R.attr.media_preview_unloaded_drawable, android.R.color.black)
|
||||
);
|
||||
}
|
||||
|
||||
protected abstract int getMediaPreviewHeight(Context context);
|
||||
|
@ -234,14 +237,13 @@ public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder {
|
|||
private void setAvatar(String url,
|
||||
@Nullable String rebloggedUrl,
|
||||
boolean isBot,
|
||||
boolean showBotOverlay,
|
||||
boolean animateAvatar) {
|
||||
StatusDisplayOptions statusDisplayOptions) {
|
||||
|
||||
int avatarRadius;
|
||||
if (TextUtils.isEmpty(rebloggedUrl)) {
|
||||
avatar.setPaddingRelative(0, 0, 0, 0);
|
||||
|
||||
if (showBotOverlay && isBot) {
|
||||
if (statusDisplayOptions.showBotOverlay() && isBot) {
|
||||
avatarInset.setVisibility(View.VISIBLE);
|
||||
avatarInset.setBackgroundColor(0x50ffffff);
|
||||
Glide.with(avatarInset)
|
||||
|
@ -260,12 +262,14 @@ public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder {
|
|||
|
||||
avatarInset.setVisibility(View.VISIBLE);
|
||||
avatarInset.setBackground(null);
|
||||
ImageLoadingHelper.loadAvatar(rebloggedUrl, avatarInset, avatarRadius24dp, animateAvatar);
|
||||
ImageLoadingHelper.loadAvatar(rebloggedUrl, avatarInset, avatarRadius24dp,
|
||||
statusDisplayOptions.animateAvatars());
|
||||
|
||||
avatarRadius = avatarRadius36dp;
|
||||
}
|
||||
|
||||
ImageLoadingHelper.loadAvatar(url, avatar, avatarRadius, animateAvatar);
|
||||
ImageLoadingHelper.loadAvatar(url, avatar, avatarRadius,
|
||||
statusDisplayOptions.animateAvatars());
|
||||
|
||||
}
|
||||
|
||||
|
@ -273,7 +277,7 @@ public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder {
|
|||
if (useAbsoluteTime) {
|
||||
timestampInfo.setText(getAbsoluteTime(createdAt));
|
||||
} else {
|
||||
if(createdAt == null) {
|
||||
if (createdAt == null) {
|
||||
timestampInfo.setText("?m");
|
||||
} else {
|
||||
long then = createdAt.getTime();
|
||||
|
@ -285,7 +289,7 @@ public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder {
|
|||
}
|
||||
|
||||
private String getAbsoluteTime(Date createdAt) {
|
||||
if(createdAt == null) {
|
||||
if (createdAt == null) {
|
||||
return "??:??:??";
|
||||
}
|
||||
if (DateUtils.isToday(createdAt.getTime())) {
|
||||
|
@ -302,7 +306,7 @@ public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder {
|
|||
/* This one is for screen-readers. Frequently, they would mispronounce timestamps like "17m"
|
||||
* as 17 meters instead of minutes. */
|
||||
|
||||
if(createdAt == null) {
|
||||
if (createdAt == null) {
|
||||
return "? minutes";
|
||||
} else {
|
||||
long then = createdAt.getTime();
|
||||
|
@ -367,12 +371,22 @@ public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder {
|
|||
bookmarkButton.setChecked(bookmarked);
|
||||
}
|
||||
|
||||
private void loadImage(MediaPreviewImageView imageView, String previewUrl, MetaData meta) {
|
||||
private BitmapDrawable decodeBlurHash(String blurhash) {
|
||||
return ImageLoadingHelper.decodeBlurHash(this.avatar.getContext(), blurhash);
|
||||
}
|
||||
|
||||
private void loadImage(MediaPreviewImageView imageView, String previewUrl, MetaData meta,
|
||||
@Nullable String blurhash) {
|
||||
Drawable placeholder = blurhash != null ? decodeBlurHash(blurhash) : mediaPreviewUnloaded;
|
||||
if (TextUtils.isEmpty(previewUrl)) {
|
||||
Glide.with(imageView)
|
||||
.load(mediaPreviewUnloadedId)
|
||||
.centerInside()
|
||||
.into(imageView);
|
||||
if (blurhash != null) {
|
||||
imageView.setImageDrawable(decodeBlurHash(blurhash));
|
||||
} else {
|
||||
Glide.with(imageView)
|
||||
.load(placeholder)
|
||||
.centerInside()
|
||||
.into(imageView);
|
||||
}
|
||||
} else {
|
||||
Focus focus = meta != null ? meta.getFocus() : null;
|
||||
|
||||
|
@ -381,7 +395,7 @@ public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder {
|
|||
|
||||
Glide.with(imageView)
|
||||
.load(previewUrl)
|
||||
.placeholder(mediaPreviewUnloadedId)
|
||||
.placeholder(placeholder)
|
||||
.centerInside()
|
||||
.addListener(imageView)
|
||||
.into(imageView);
|
||||
|
@ -390,7 +404,7 @@ public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder {
|
|||
|
||||
Glide.with(imageView)
|
||||
.load(previewUrl)
|
||||
.placeholder(mediaPreviewUnloadedId)
|
||||
.placeholder(placeholder)
|
||||
.centerInside()
|
||||
.into(imageView);
|
||||
}
|
||||
|
@ -398,39 +412,11 @@ public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder {
|
|||
}
|
||||
|
||||
protected void setMediaPreviews(final List<Attachment> attachments, boolean sensitive,
|
||||
final StatusActionListener listener, boolean showingContent) {
|
||||
final StatusActionListener listener, boolean showingContent,
|
||||
boolean useBlurhash) {
|
||||
Context context = itemView.getContext();
|
||||
final int n = Math.min(attachments.size(), Status.MAX_MEDIA_ATTACHMENTS);
|
||||
|
||||
for (int i = 0; i < n; i++) {
|
||||
String previewUrl = attachments.get(i).getPreviewUrl();
|
||||
String description = attachments.get(i).getDescription();
|
||||
MediaPreviewImageView imageView = mediaPreviews[i];
|
||||
|
||||
imageView.setVisibility(View.VISIBLE);
|
||||
|
||||
if (TextUtils.isEmpty(description)) {
|
||||
imageView.setContentDescription(imageView.getContext()
|
||||
.getString(R.string.action_view_media));
|
||||
} else {
|
||||
imageView.setContentDescription(description);
|
||||
}
|
||||
|
||||
if (!sensitive || showingContent) {
|
||||
loadImage(imageView, previewUrl, attachments.get(i).getMeta());
|
||||
} else {
|
||||
imageView.setImageResource(mediaPreviewUnloadedId);
|
||||
}
|
||||
|
||||
final Attachment.Type type = attachments.get(i).getType();
|
||||
if (type == Attachment.Type.VIDEO || type == Attachment.Type.GIFV) {
|
||||
mediaOverlays[i].setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
mediaOverlays[i].setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
setAttachmentClickListener(imageView, listener, i, attachments.get(i), true);
|
||||
}
|
||||
|
||||
final int mediaPreviewHeight = getMediaPreviewHeight(context);
|
||||
|
||||
|
@ -444,15 +430,51 @@ public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder {
|
|||
mediaPreviews[3].getLayoutParams().height = mediaPreviewHeight;
|
||||
}
|
||||
|
||||
for (int i = 0; i < n; i++) {
|
||||
Attachment attachment = attachments.get(i);
|
||||
String previewUrl = attachment.getPreviewUrl();
|
||||
String description = attachment.getDescription();
|
||||
MediaPreviewImageView imageView = mediaPreviews[i];
|
||||
|
||||
imageView.setVisibility(View.VISIBLE);
|
||||
|
||||
if (TextUtils.isEmpty(description)) {
|
||||
imageView.setContentDescription(imageView.getContext()
|
||||
.getString(R.string.action_view_media));
|
||||
} else {
|
||||
imageView.setContentDescription(description);
|
||||
}
|
||||
|
||||
if (showingContent) {
|
||||
loadImage(imageView, previewUrl, attachment.getMeta(), attachment.getBlurhash());
|
||||
} else {
|
||||
imageView.setFocalPoint(null);
|
||||
imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
|
||||
if (useBlurhash && attachment.getBlurhash() != null) {
|
||||
BitmapDrawable blurhashBitmap = decodeBlurHash(attachment.getBlurhash());
|
||||
imageView.setImageDrawable(blurhashBitmap);
|
||||
} else {
|
||||
imageView.setImageDrawable(new ColorDrawable(ThemeUtils.getColor(
|
||||
context, R.attr.sensitive_media_warning_background_color)));
|
||||
}
|
||||
}
|
||||
|
||||
final Attachment.Type type = attachment.getType();
|
||||
if (showingContent && (type == Attachment.Type.VIDEO || type == Attachment.Type.GIFV)) {
|
||||
mediaOverlays[i].setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
mediaOverlays[i].setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
setAttachmentClickListener(imageView, listener, i, attachment, true);
|
||||
}
|
||||
|
||||
|
||||
final String hiddenContentText;
|
||||
if (sensitive) {
|
||||
hiddenContentText = context.getString(R.string.status_sensitive_media_template,
|
||||
context.getString(R.string.status_sensitive_media_title),
|
||||
context.getString(R.string.status_sensitive_media_directions));
|
||||
hiddenContentText = context.getString(R.string.status_sensitive_media_title);
|
||||
} else {
|
||||
hiddenContentText = context.getString(R.string.status_sensitive_media_template,
|
||||
context.getString(R.string.status_media_hidden_title),
|
||||
context.getString(R.string.status_sensitive_media_directions));
|
||||
hiddenContentText = context.getString(R.string.status_media_hidden_title);
|
||||
}
|
||||
|
||||
sensitiveMediaWarning.setText(HtmlUtils.fromHtml(hiddenContentText));
|
||||
|
@ -528,7 +550,11 @@ public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder {
|
|||
view.setOnClickListener(v -> {
|
||||
int position = getAdapterPosition();
|
||||
if (position != RecyclerView.NO_POSITION) {
|
||||
listener.onViewMedia(position, index, animateTransition ? v : null);
|
||||
if (sensitiveMediaWarning.getVisibility() == View.VISIBLE) {
|
||||
listener.onContentHiddenChange(true, getAdapterPosition());
|
||||
} else {
|
||||
listener.onViewMedia(position, index, animateTransition ? v : null);
|
||||
}
|
||||
}
|
||||
});
|
||||
view.setOnLongClickListener(v -> {
|
||||
|
@ -540,7 +566,7 @@ public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder {
|
|||
|
||||
private static CharSequence getAttachmentDescription(Context context, Attachment attachment) {
|
||||
String duration = "";
|
||||
if(attachment.getMeta() != null && attachment.getMeta().getDuration() != null && attachment.getMeta().getDuration() > 0) {
|
||||
if (attachment.getMeta() != null && attachment.getMeta().getDuration() != null && attachment.getMeta().getDuration() > 0) {
|
||||
duration = formatDuration(attachment.getMeta().getDuration()) + " ";
|
||||
}
|
||||
if (TextUtils.isEmpty(attachment.getDescription())) {
|
||||
|
@ -608,29 +634,27 @@ public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder {
|
|||
}
|
||||
|
||||
public void setupWithStatus(StatusViewData.Concrete status, final StatusActionListener listener,
|
||||
boolean mediaPreviewEnabled, boolean showBotOverlay, boolean animateAvatar) {
|
||||
this.setupWithStatus(status, listener, mediaPreviewEnabled, showBotOverlay, animateAvatar, null);
|
||||
StatusDisplayOptions statusDisplayOptions) {
|
||||
this.setupWithStatus(status, listener, statusDisplayOptions, null);
|
||||
}
|
||||
|
||||
protected void setupWithStatus(StatusViewData.Concrete status,
|
||||
final StatusActionListener listener,
|
||||
boolean mediaPreviewEnabled,
|
||||
boolean showBotOverlay,
|
||||
boolean animateAvatar,
|
||||
StatusDisplayOptions statusDisplayOptions,
|
||||
@Nullable Object payloads) {
|
||||
if (payloads == null) {
|
||||
setDisplayName(status.getUserFullName(), status.getAccountEmojis());
|
||||
setUsername(status.getNickname());
|
||||
setCreatedAt(status.getCreatedAt());
|
||||
setIsReply(status.getInReplyToId() != null);
|
||||
setAvatar(status.getAvatar(), status.getRebloggedAvatar(), status.isBot(), showBotOverlay, animateAvatar);
|
||||
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();
|
||||
if (mediaPreviewEnabled && !hasAudioAttachment(attachments)) {
|
||||
setMediaPreviews(attachments, sensitive, listener, status.isShowingContent());
|
||||
if (statusDisplayOptions.mediaPreviewEnabled() && !hasAudioAttachment(attachments)) {
|
||||
setMediaPreviews(attachments, sensitive, listener, status.isShowingContent(), statusDisplayOptions.useBlurhash());
|
||||
|
||||
if (attachments.size() == 0) {
|
||||
hideSensitiveMediaWarning();
|
||||
|
@ -674,7 +698,7 @@ public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder {
|
|||
}
|
||||
|
||||
protected static boolean hasAudioAttachment(List<Attachment> attachments) {
|
||||
for(Attachment attachment: attachments) {
|
||||
for (Attachment attachment : attachments) {
|
||||
if (attachment.getType() == Attachment.Type.AUDIO) {
|
||||
return true;
|
||||
}
|
||||
|
@ -747,7 +771,7 @@ public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder {
|
|||
|
||||
private static CharSequence getVisibilityDescription(Context context, Status.Visibility visibility) {
|
||||
|
||||
if(visibility == null) {
|
||||
if (visibility == null) {
|
||||
return "";
|
||||
}
|
||||
|
||||
|
|
|
@ -16,6 +16,9 @@ import android.widget.LinearLayout;
|
|||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.bumptech.glide.Glide;
|
||||
import com.bumptech.glide.load.resource.bitmap.CenterCrop;
|
||||
import com.bumptech.glide.load.resource.bitmap.GranularRoundedCorners;
|
||||
|
@ -25,14 +28,12 @@ import com.keylesspalace.tusky.entity.Status;
|
|||
import com.keylesspalace.tusky.interfaces.StatusActionListener;
|
||||
import com.keylesspalace.tusky.util.CustomURLSpan;
|
||||
import com.keylesspalace.tusky.util.LinkHelper;
|
||||
import com.keylesspalace.tusky.util.StatusDisplayOptions;
|
||||
import com.keylesspalace.tusky.viewdata.StatusViewData;
|
||||
|
||||
import java.text.DateFormat;
|
||||
import java.util.Date;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
class StatusDetailedViewHolder extends StatusBaseViewHolder {
|
||||
private TextView reblogs;
|
||||
private TextView favourites;
|
||||
|
@ -44,8 +45,8 @@ class StatusDetailedViewHolder extends StatusBaseViewHolder {
|
|||
private TextView cardUrl;
|
||||
private View infoDivider;
|
||||
|
||||
StatusDetailedViewHolder(View view, boolean useAbsoluteTime) {
|
||||
super(view, useAbsoluteTime);
|
||||
StatusDetailedViewHolder(View view) {
|
||||
super(view);
|
||||
reblogs = view.findViewById(R.id.status_reblogs);
|
||||
favourites = view.findViewById(R.id.status_favourites);
|
||||
cardView = view.findViewById(R.id.card_view);
|
||||
|
@ -125,10 +126,11 @@ class StatusDetailedViewHolder extends StatusBaseViewHolder {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected void setupWithStatus(final StatusViewData.Concrete status, final StatusActionListener listener,
|
||||
boolean mediaPreviewEnabled, boolean showBotOverlay, boolean animateAvatar,
|
||||
protected void setupWithStatus(final StatusViewData.Concrete status,
|
||||
final StatusActionListener listener,
|
||||
StatusDisplayOptions statusDisplayOptions,
|
||||
@Nullable Object payloads) {
|
||||
super.setupWithStatus(status, listener, mediaPreviewEnabled, showBotOverlay, animateAvatar, payloads);
|
||||
super.setupWithStatus(status, listener, statusDisplayOptions, payloads);
|
||||
if (payloads == null) {
|
||||
setReblogAndFavCount(status.getReblogsCount(), status.getFavouritesCount(), listener);
|
||||
|
||||
|
|
|
@ -22,14 +22,15 @@ import android.view.View;
|
|||
import android.widget.TextView;
|
||||
import android.widget.ToggleButton;
|
||||
|
||||
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.SmartLengthInputFilter;
|
||||
import com.keylesspalace.tusky.util.StatusDisplayOptions;
|
||||
import com.keylesspalace.tusky.viewdata.StatusViewData;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import at.connyduck.sparkbutton.helpers.Utils;
|
||||
|
||||
public class StatusViewHolder extends StatusBaseViewHolder {
|
||||
|
@ -39,8 +40,8 @@ public class StatusViewHolder extends StatusBaseViewHolder {
|
|||
private TextView statusInfo;
|
||||
private ToggleButton contentCollapseButton;
|
||||
|
||||
public StatusViewHolder(View itemView, boolean useAbsoluteTime) {
|
||||
super(itemView, useAbsoluteTime);
|
||||
public StatusViewHolder(View itemView) {
|
||||
super(itemView);
|
||||
statusInfo = itemView.findViewById(R.id.status_info);
|
||||
contentCollapseButton = itemView.findViewById(R.id.button_toggle_content);
|
||||
}
|
||||
|
@ -51,8 +52,9 @@ public class StatusViewHolder extends StatusBaseViewHolder {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected void setupWithStatus(StatusViewData.Concrete status, final StatusActionListener listener,
|
||||
boolean mediaPreviewEnabled, boolean showBotOverlay, boolean animateAvatar,
|
||||
protected void setupWithStatus(StatusViewData.Concrete status,
|
||||
final StatusActionListener listener,
|
||||
StatusDisplayOptions statusDisplayOptions,
|
||||
@Nullable Object payloads) {
|
||||
if (payloads == null) {
|
||||
|
||||
|
@ -67,7 +69,7 @@ public class StatusViewHolder extends StatusBaseViewHolder {
|
|||
}
|
||||
|
||||
}
|
||||
super.setupWithStatus(status, listener, mediaPreviewEnabled, showBotOverlay, animateAvatar, payloads);
|
||||
super.setupWithStatus(status, listener, statusDisplayOptions, payloads);
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -15,15 +15,17 @@
|
|||
|
||||
package com.keylesspalace.tusky.adapter;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
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.ArrayList;
|
||||
|
@ -34,20 +36,14 @@ public class ThreadAdapter extends RecyclerView.Adapter {
|
|||
private static final int VIEW_TYPE_STATUS_DETAILED = 1;
|
||||
|
||||
private List<StatusViewData.Concrete> statuses;
|
||||
private StatusDisplayOptions statusDisplayOptions;
|
||||
private StatusActionListener statusActionListener;
|
||||
private boolean mediaPreviewEnabled;
|
||||
private boolean useAbsoluteTime;
|
||||
private boolean showBotOverlay;
|
||||
private boolean animateAvatar;
|
||||
private int detailedStatusPosition;
|
||||
|
||||
public ThreadAdapter(StatusActionListener listener) {
|
||||
public ThreadAdapter(StatusDisplayOptions statusDisplayOptions, StatusActionListener listener) {
|
||||
this.statusDisplayOptions = statusDisplayOptions;
|
||||
this.statusActionListener = listener;
|
||||
this.statuses = new ArrayList<>();
|
||||
mediaPreviewEnabled = true;
|
||||
useAbsoluteTime = false;
|
||||
showBotOverlay = true;
|
||||
animateAvatar = false;
|
||||
detailedStatusPosition = RecyclerView.NO_POSITION;
|
||||
}
|
||||
|
||||
|
@ -59,12 +55,12 @@ public class ThreadAdapter extends RecyclerView.Adapter {
|
|||
case VIEW_TYPE_STATUS: {
|
||||
View view = LayoutInflater.from(parent.getContext())
|
||||
.inflate(R.layout.item_status, parent, false);
|
||||
return new StatusViewHolder(view, useAbsoluteTime);
|
||||
return new StatusViewHolder(view);
|
||||
}
|
||||
case VIEW_TYPE_STATUS_DETAILED: {
|
||||
View view = LayoutInflater.from(parent.getContext())
|
||||
.inflate(R.layout.item_status_detailed, parent, false);
|
||||
return new StatusDetailedViewHolder(view, useAbsoluteTime);
|
||||
return new StatusDetailedViewHolder(view);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -74,10 +70,10 @@ public class ThreadAdapter extends RecyclerView.Adapter {
|
|||
StatusViewData.Concrete status = statuses.get(position);
|
||||
if (position == detailedStatusPosition) {
|
||||
StatusDetailedViewHolder holder = (StatusDetailedViewHolder) viewHolder;
|
||||
holder.setupWithStatus(status, statusActionListener, mediaPreviewEnabled, showBotOverlay, animateAvatar);
|
||||
holder.setupWithStatus(status, statusActionListener, statusDisplayOptions);
|
||||
} else {
|
||||
StatusViewHolder holder = (StatusViewHolder) viewHolder;
|
||||
holder.setupWithStatus(status, statusActionListener, mediaPreviewEnabled, showBotOverlay, animateAvatar);
|
||||
holder.setupWithStatus(status, statusActionListener, statusDisplayOptions);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -151,22 +147,6 @@ public class ThreadAdapter extends RecyclerView.Adapter {
|
|||
}
|
||||
}
|
||||
|
||||
public void setMediaPreviewEnabled(boolean enabled) {
|
||||
mediaPreviewEnabled = enabled;
|
||||
}
|
||||
|
||||
public void setUseAbsoluteTime(boolean useAbsoluteTime) {
|
||||
this.useAbsoluteTime = useAbsoluteTime;
|
||||
}
|
||||
|
||||
public void setShowBotOverlay(boolean showBotOverlay) {
|
||||
this.showBotOverlay = showBotOverlay;
|
||||
}
|
||||
|
||||
public void setAnimateAvatar(boolean animateAvatar) {
|
||||
this.animateAvatar = animateAvatar;
|
||||
}
|
||||
|
||||
public void setDetailedStatusPosition(int position) {
|
||||
if (position != detailedStatusPosition
|
||||
&& detailedStatusPosition != RecyclerView.NO_POSITION) {
|
||||
|
|
|
@ -15,19 +15,21 @@
|
|||
|
||||
package com.keylesspalace.tusky.adapter;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import java.util.List;
|
||||
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> {
|
||||
|
@ -40,20 +42,29 @@ public final class TimelineAdapter extends RecyclerView.Adapter {
|
|||
private static final int VIEW_TYPE_PLACEHOLDER = 2;
|
||||
|
||||
private final AdapterDataSource<StatusViewData> dataSource;
|
||||
private StatusDisplayOptions statusDisplayOptions;
|
||||
private final StatusActionListener statusListener;
|
||||
private boolean mediaPreviewEnabled;
|
||||
private boolean useAbsoluteTime;
|
||||
private boolean showBotOverlay;
|
||||
private boolean animateAvatar;
|
||||
|
||||
public TimelineAdapter(AdapterDataSource<StatusViewData> dataSource,
|
||||
StatusDisplayOptions statusDisplayOptions,
|
||||
StatusActionListener statusListener) {
|
||||
this.dataSource = dataSource;
|
||||
this.statusDisplayOptions = statusDisplayOptions;
|
||||
this.statusListener = statusListener;
|
||||
mediaPreviewEnabled = true;
|
||||
useAbsoluteTime = false;
|
||||
showBotOverlay = true;
|
||||
animateAvatar = false;
|
||||
}
|
||||
|
||||
public boolean getMediaPreviewEnabled() {
|
||||
return statusDisplayOptions.mediaPreviewEnabled();
|
||||
}
|
||||
|
||||
public void setMediaPreviewEnabled(boolean mediaPreviewEnabled) {
|
||||
this.statusDisplayOptions = statusDisplayOptions.copy(
|
||||
statusDisplayOptions.animateAvatars(),
|
||||
mediaPreviewEnabled,
|
||||
statusDisplayOptions.useAbsoluteTime(),
|
||||
statusDisplayOptions.showBotOverlay(),
|
||||
statusDisplayOptions.useBlurhash()
|
||||
);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
|
@ -64,7 +75,7 @@ public final class TimelineAdapter extends RecyclerView.Adapter {
|
|||
case VIEW_TYPE_STATUS: {
|
||||
View view = LayoutInflater.from(viewGroup.getContext())
|
||||
.inflate(R.layout.item_status, viewGroup, false);
|
||||
return new StatusViewHolder(view, useAbsoluteTime);
|
||||
return new StatusViewHolder(view);
|
||||
}
|
||||
case VIEW_TYPE_PLACEHOLDER: {
|
||||
View view = LayoutInflater.from(viewGroup.getContext())
|
||||
|
@ -76,16 +87,16 @@ public final class TimelineAdapter extends RecyclerView.Adapter {
|
|||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, int position) {
|
||||
bindViewHolder(viewHolder,position,null);
|
||||
bindViewHolder(viewHolder, position, null);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, int position, @NonNull List payloads) {
|
||||
bindViewHolder(viewHolder,position,payloads);
|
||||
bindViewHolder(viewHolder, position, payloads);
|
||||
}
|
||||
|
||||
private void bindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, int position, @Nullable List 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;
|
||||
|
@ -94,12 +105,11 @@ public final class TimelineAdapter extends RecyclerView.Adapter {
|
|||
StatusViewHolder holder = (StatusViewHolder) viewHolder;
|
||||
holder.setupWithStatus((StatusViewData.Concrete) status,
|
||||
statusListener,
|
||||
mediaPreviewEnabled,
|
||||
showBotOverlay,
|
||||
animateAvatar,
|
||||
statusDisplayOptions,
|
||||
payloads != null && !payloads.isEmpty() ? payloads.get(0) : null);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return dataSource.getItemCount();
|
||||
|
@ -114,26 +124,6 @@ public final class TimelineAdapter extends RecyclerView.Adapter {
|
|||
}
|
||||
}
|
||||
|
||||
public void setMediaPreviewEnabled(boolean enabled) {
|
||||
mediaPreviewEnabled = enabled;
|
||||
}
|
||||
|
||||
public void setUseAbsoluteTime(boolean useAbsoluteTime){
|
||||
this.useAbsoluteTime = useAbsoluteTime;
|
||||
}
|
||||
|
||||
public boolean getMediaPreviewEnabled() {
|
||||
return mediaPreviewEnabled;
|
||||
}
|
||||
|
||||
public void setShowBotOverlay(boolean showBotOverlay) {
|
||||
this.showBotOverlay = showBotOverlay;
|
||||
}
|
||||
|
||||
public void setAnimateAvatar(boolean animateAvatar) {
|
||||
this.animateAvatar = animateAvatar;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getItemId(int position) {
|
||||
return dataSource.getItemAt(position).getViewDataId();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue