Adds option to hide media previews if reduced data usage is desired Closes #56.
This commit is contained in:
parent
3a4ef00dab
commit
3f54ead962
12 changed files with 368 additions and 186 deletions
|
@ -37,7 +37,6 @@ import com.keylesspalace.tusky.interfaces.StatusActionListener;
|
|||
import com.squareup.picasso.Picasso;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
public class NotificationsAdapter extends RecyclerView.Adapter implements AdapterItemRemover {
|
||||
|
@ -56,6 +55,7 @@ public class NotificationsAdapter extends RecyclerView.Adapter implements Adapte
|
|||
private StatusActionListener statusListener;
|
||||
private NotificationActionListener notificationActionListener;
|
||||
private FooterState footerState = FooterState.END;
|
||||
private boolean mediaPreviewEnabled;
|
||||
|
||||
public NotificationsAdapter(StatusActionListener statusListener,
|
||||
NotificationActionListener notificationActionListener) {
|
||||
|
@ -63,15 +63,7 @@ public class NotificationsAdapter extends RecyclerView.Adapter implements Adapte
|
|||
notifications = new ArrayList<>();
|
||||
this.statusListener = statusListener;
|
||||
this.notificationActionListener = notificationActionListener;
|
||||
}
|
||||
|
||||
|
||||
public void setFooterState(FooterState newFooterState) {
|
||||
FooterState oldValue = footerState;
|
||||
footerState = newFooterState;
|
||||
if (footerState != oldValue) {
|
||||
notifyItemChanged(notifications.size());
|
||||
}
|
||||
mediaPreviewEnabled = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -126,7 +118,7 @@ public class NotificationsAdapter extends RecyclerView.Adapter implements Adapte
|
|||
case MENTION: {
|
||||
StatusViewHolder holder = (StatusViewHolder) viewHolder;
|
||||
Status status = notification.status;
|
||||
holder.setupWithStatus(status, statusListener);
|
||||
holder.setupWithStatus(status, statusListener, mediaPreviewEnabled);
|
||||
break;
|
||||
}
|
||||
case FAVOURITE:
|
||||
|
@ -139,8 +131,8 @@ public class NotificationsAdapter extends RecyclerView.Adapter implements Adapte
|
|||
}
|
||||
case FOLLOW: {
|
||||
FollowViewHolder holder = (FollowViewHolder) viewHolder;
|
||||
holder.setMessage(notification.account.getDisplayName(), notification.account.username,
|
||||
notification.account.avatar);
|
||||
holder.setMessage(notification.account.getDisplayName(),
|
||||
notification.account.username, notification.account.avatar);
|
||||
holder.setupButtons(notificationActionListener, notification.account.id);
|
||||
break;
|
||||
}
|
||||
|
@ -175,6 +167,25 @@ public class NotificationsAdapter extends RecyclerView.Adapter implements Adapte
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeItem(int position) {
|
||||
notifications.remove(position);
|
||||
notifyItemChanged(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeAllByAccountId(String id) {
|
||||
for (int i = 0; i < notifications.size();) {
|
||||
Notification notification = notifications.get(i);
|
||||
if (id.equals(notification.account.id)) {
|
||||
notifications.remove(i);
|
||||
notifyItemRemoved(i);
|
||||
} else {
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public @Nullable Notification getItem(int position) {
|
||||
if (position >= 0 && position < notifications.size()) {
|
||||
return notifications.get(position);
|
||||
|
@ -209,25 +220,23 @@ public class NotificationsAdapter extends RecyclerView.Adapter implements Adapte
|
|||
notifyItemRangeInserted(end, new_notifications.size());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeItem(int position) {
|
||||
notifications.remove(position);
|
||||
notifyItemChanged(position);
|
||||
public void clear() {
|
||||
notifications.clear();
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeAllByAccountId(String id) {
|
||||
for (int i = 0; i < notifications.size();) {
|
||||
Notification notification = notifications.get(i);
|
||||
if (id.equals(notification.account.id)) {
|
||||
notifications.remove(i);
|
||||
notifyItemRemoved(i);
|
||||
} else {
|
||||
i += 1;
|
||||
}
|
||||
public void setFooterState(FooterState newFooterState) {
|
||||
FooterState oldValue = footerState;
|
||||
footerState = newFooterState;
|
||||
if (footerState != oldValue) {
|
||||
notifyItemChanged(notifications.size());
|
||||
}
|
||||
}
|
||||
|
||||
public void setMediaPreviewEnabled(boolean enabled) {
|
||||
mediaPreviewEnabled = enabled;
|
||||
}
|
||||
|
||||
public interface NotificationActionListener {
|
||||
void onViewAccount(String id);
|
||||
}
|
||||
|
|
|
@ -16,8 +16,11 @@
|
|||
package com.keylesspalace.tusky.adapter;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.support.annotation.DrawableRes;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v4.content.ContextCompat;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.text.Spanned;
|
||||
import android.view.View;
|
||||
|
@ -60,6 +63,7 @@ class StatusViewHolder extends RecyclerView.ViewHolder {
|
|||
private ImageView mediaPreview2;
|
||||
private ImageView mediaPreview3;
|
||||
private View sensitiveMediaWarning;
|
||||
private TextView mediaLabel;
|
||||
private View contentWarningBar;
|
||||
private TextView contentWarningDescription;
|
||||
private ToggleButton contentWarningButton;
|
||||
|
@ -85,6 +89,7 @@ class StatusViewHolder extends RecyclerView.ViewHolder {
|
|||
mediaPreview2 = (ImageView) itemView.findViewById(R.id.status_media_preview_2);
|
||||
mediaPreview3 = (ImageView) itemView.findViewById(R.id.status_media_preview_3);
|
||||
sensitiveMediaWarning = itemView.findViewById(R.id.status_sensitive_media_warning);
|
||||
mediaLabel = (TextView) itemView.findViewById(R.id.status_media_label);
|
||||
contentWarningBar = itemView.findViewById(R.id.status_content_warning_bar);
|
||||
contentWarningDescription =
|
||||
(TextView) itemView.findViewById(R.id.status_content_warning_description);
|
||||
|
@ -187,8 +192,8 @@ class StatusViewHolder extends RecyclerView.ViewHolder {
|
|||
favouriteButton.setChecked(favourited);
|
||||
}
|
||||
|
||||
private void setMediaPreviews(final Status.MediaAttachment[] attachments,
|
||||
boolean sensitive, final StatusActionListener listener) {
|
||||
private void setMediaPreviews(final Status.MediaAttachment[] attachments, boolean sensitive,
|
||||
final StatusActionListener listener) {
|
||||
final ImageView[] previews = {
|
||||
mediaPreview0,
|
||||
mediaPreview1,
|
||||
|
@ -212,7 +217,7 @@ class StatusViewHolder extends RecyclerView.ViewHolder {
|
|||
|
||||
previews[i].setVisibility(View.VISIBLE);
|
||||
|
||||
if(previewUrl == null || previewUrl.isEmpty()) {
|
||||
if (previewUrl == null || previewUrl.isEmpty()) {
|
||||
Picasso.with(context)
|
||||
.load(mediaPreviewUnloadedId)
|
||||
.into(previews[i]);
|
||||
|
@ -254,6 +259,62 @@ class StatusViewHolder extends RecyclerView.ViewHolder {
|
|||
}
|
||||
}
|
||||
|
||||
private static String getLabelTypeText(Context context, Status.MediaAttachment.Type type) {
|
||||
switch (type) {
|
||||
default:
|
||||
case IMAGE: return context.getString(R.string.status_media_images);
|
||||
case GIFV:
|
||||
case VIDEO: return context.getString(R.string.status_media_video);
|
||||
}
|
||||
}
|
||||
|
||||
private static @DrawableRes int getLabelIcon(Status.MediaAttachment.Type type) {
|
||||
switch (type) {
|
||||
default:
|
||||
case IMAGE: return R.drawable.ic_photo_24dp;
|
||||
case GIFV:
|
||||
case VIDEO: return R.drawable.ic_videocam_24dp;
|
||||
}
|
||||
}
|
||||
|
||||
private void setMediaLabel(Status.MediaAttachment[] attachments, boolean sensitive,
|
||||
final StatusActionListener listener) {
|
||||
if (attachments.length == 0) {
|
||||
mediaLabel.setVisibility(View.GONE);
|
||||
return;
|
||||
}
|
||||
mediaLabel.setVisibility(View.VISIBLE);
|
||||
|
||||
// Set the label's text.
|
||||
Context context = itemView.getContext();
|
||||
String labelText = getLabelTypeText(context, attachments[0].type);
|
||||
if (sensitive) {
|
||||
String sensitiveText = context.getString(R.string.status_sensitive_media_title);
|
||||
labelText += String.format(" (%s)", sensitiveText);
|
||||
}
|
||||
mediaLabel.setText(labelText);
|
||||
|
||||
// Set the icon next to the label.
|
||||
int drawableId = getLabelIcon(attachments[0].type);
|
||||
Drawable drawable = ContextCompat.getDrawable(context, drawableId);
|
||||
ThemeUtils.setDrawableTint(context, drawable, android.R.attr.textColorTertiary);
|
||||
mediaLabel.setCompoundDrawablesWithIntrinsicBounds(drawable, null, null, null);
|
||||
|
||||
// Set the listener for the media view action.
|
||||
int n = Math.min(attachments.length, Status.MAX_MEDIA_ATTACHMENTS);
|
||||
final String[] urls = new String[n];
|
||||
for (int i = 0; i < n; i++) {
|
||||
urls[i] = attachments[i].url;
|
||||
}
|
||||
final Status.MediaAttachment.Type type = attachments[0].type;
|
||||
mediaLabel.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
listener.onViewMedia(urls, 0, type);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void hideSensitiveMediaWarning() {
|
||||
sensitiveMediaWarning.setVisibility(View.GONE);
|
||||
}
|
||||
|
@ -302,20 +363,20 @@ class StatusViewHolder extends RecyclerView.ViewHolder {
|
|||
}
|
||||
});
|
||||
reblogButton.setEventListener(new SparkEventListener() {
|
||||
@Override
|
||||
public void onEvent(ImageView button, boolean buttonState) {
|
||||
int position = getAdapterPosition();
|
||||
if (position != RecyclerView.NO_POSITION) {
|
||||
listener.onReblog(!reblogged, position);
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void onEvent(ImageView button, boolean buttonState) {
|
||||
int position = getAdapterPosition();
|
||||
if (position != RecyclerView.NO_POSITION) {
|
||||
listener.onReblog(!reblogged, position);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEventAnimationEnd(ImageView button, boolean buttonState) {}
|
||||
@Override
|
||||
public void onEventAnimationEnd(ImageView button, boolean buttonState) {}
|
||||
|
||||
@Override
|
||||
public void onEventAnimationStart(ImageView button, boolean buttonState) {}
|
||||
});
|
||||
@Override
|
||||
public void onEventAnimationStart(ImageView button, boolean buttonState) {}
|
||||
});
|
||||
favouriteButton.setEventListener(new SparkEventListener() {
|
||||
@Override
|
||||
public void onEvent(ImageView button, boolean buttonState) {
|
||||
|
@ -357,7 +418,8 @@ class StatusViewHolder extends RecyclerView.ViewHolder {
|
|||
container.setOnClickListener(viewThreadListener);
|
||||
}
|
||||
|
||||
void setupWithStatus(Status status, StatusActionListener listener) {
|
||||
void setupWithStatus(Status status, StatusActionListener listener,
|
||||
boolean mediaPreviewEnabled) {
|
||||
Status realStatus = status.getActionableStatus();
|
||||
|
||||
setDisplayName(realStatus.account.getDisplayName());
|
||||
|
@ -375,12 +437,25 @@ class StatusViewHolder extends RecyclerView.ViewHolder {
|
|||
}
|
||||
Status.MediaAttachment[] attachments = realStatus.attachments;
|
||||
boolean sensitive = realStatus.sensitive;
|
||||
setMediaPreviews(attachments, sensitive, listener);
|
||||
/* A status without attachments is sometimes still marked sensitive, so it's necessary to
|
||||
* check both whether there are any attachments and if it's marked sensitive. */
|
||||
if (!sensitive || attachments.length == 0) {
|
||||
if (mediaPreviewEnabled) {
|
||||
setMediaPreviews(attachments, sensitive, listener);
|
||||
/* A status without attachments is sometimes still marked sensitive, so it's necessary
|
||||
* to check both whether there are any attachments and if it's marked sensitive. */
|
||||
if (!sensitive || attachments.length == 0) {
|
||||
hideSensitiveMediaWarning();
|
||||
}
|
||||
// Hide the unused label.
|
||||
mediaLabel.setVisibility(View.GONE);
|
||||
} else {
|
||||
setMediaLabel(attachments, sensitive, listener);
|
||||
// Hide all unused views.
|
||||
mediaPreview0.setVisibility(View.GONE);
|
||||
mediaPreview1.setVisibility(View.GONE);
|
||||
mediaPreview2.setVisibility(View.GONE);
|
||||
mediaPreview3.setVisibility(View.GONE);
|
||||
hideSensitiveMediaWarning();
|
||||
}
|
||||
|
||||
setupButtons(listener, realStatus.account.id);
|
||||
setRebloggingEnabled(status.rebloggingAllowed());
|
||||
if (realStatus.spoilerText.isEmpty()) {
|
||||
|
|
|
@ -32,11 +32,13 @@ public class ThreadAdapter extends RecyclerView.Adapter implements AdapterItemRe
|
|||
private List<Status> statuses;
|
||||
private StatusActionListener statusActionListener;
|
||||
private int statusIndex;
|
||||
private boolean mediaPreviewEnabled;
|
||||
|
||||
public ThreadAdapter(StatusActionListener listener) {
|
||||
this.statusActionListener = listener;
|
||||
this.statuses = new ArrayList<>();
|
||||
this.statusIndex = 0;
|
||||
mediaPreviewEnabled = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -50,7 +52,7 @@ public class ThreadAdapter extends RecyclerView.Adapter implements AdapterItemRe
|
|||
public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int position) {
|
||||
StatusViewHolder holder = (StatusViewHolder) viewHolder;
|
||||
Status status = statuses.get(position);
|
||||
holder.setupWithStatus(status, statusActionListener);
|
||||
holder.setupWithStatus(status, statusActionListener, mediaPreviewEnabled);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -58,10 +60,6 @@ public class ThreadAdapter extends RecyclerView.Adapter implements AdapterItemRe
|
|||
return statuses.size();
|
||||
}
|
||||
|
||||
public Status getItem(int position) {
|
||||
return statuses.get(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeItem(int position) {
|
||||
statuses.remove(position);
|
||||
|
@ -81,6 +79,10 @@ public class ThreadAdapter extends RecyclerView.Adapter implements AdapterItemRe
|
|||
}
|
||||
}
|
||||
|
||||
public Status getItem(int position) {
|
||||
return statuses.get(position);
|
||||
}
|
||||
|
||||
public int setStatus(Status status) {
|
||||
if (statuses.size() > 0
|
||||
&& statusIndex < statuses.size()
|
||||
|
@ -124,4 +126,14 @@ public class ThreadAdapter extends RecyclerView.Adapter implements AdapterItemRe
|
|||
statuses.addAll(descendants);
|
||||
notifyItemRangeInserted(end, descendants.size());
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
statuses.clear();
|
||||
notifyDataSetChanged();
|
||||
statusIndex = 0;
|
||||
}
|
||||
|
||||
public void setMediaPreviewEnabled(boolean enabled) {
|
||||
mediaPreviewEnabled = enabled;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -42,11 +42,13 @@ public class TimelineAdapter extends RecyclerView.Adapter implements AdapterItem
|
|||
private List<Status> statuses;
|
||||
private StatusActionListener statusListener;
|
||||
private FooterState footerState = FooterState.END;
|
||||
private boolean mediaPreviewEnabled;
|
||||
|
||||
public TimelineAdapter(StatusActionListener statusListener) {
|
||||
super();
|
||||
statuses = new ArrayList<>();
|
||||
this.statusListener = statusListener;
|
||||
mediaPreviewEnabled = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -82,20 +84,12 @@ public class TimelineAdapter extends RecyclerView.Adapter implements AdapterItem
|
|||
}
|
||||
}
|
||||
|
||||
public void setFooterState(FooterState newFooterState) {
|
||||
FooterState oldValue = footerState;
|
||||
footerState = newFooterState;
|
||||
if (footerState != oldValue) {
|
||||
notifyItemChanged(statuses.size());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int position) {
|
||||
if (position < statuses.size()) {
|
||||
StatusViewHolder holder = (StatusViewHolder) viewHolder;
|
||||
Status status = statuses.get(position);
|
||||
holder.setupWithStatus(status, statusListener);
|
||||
holder.setupWithStatus(status, statusListener, mediaPreviewEnabled);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -113,6 +107,25 @@ public class TimelineAdapter extends RecyclerView.Adapter implements AdapterItem
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeItem(int position) {
|
||||
statuses.remove(position);
|
||||
notifyItemRemoved(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeAllByAccountId(String accountId) {
|
||||
for (int i = 0; i < statuses.size();) {
|
||||
Status status = statuses.get(i);
|
||||
if (accountId.equals(status.account.id)) {
|
||||
statuses.remove(i);
|
||||
notifyItemRemoved(i);
|
||||
} else {
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void update(List<Status> newStatuses) {
|
||||
if (newStatuses == null || newStatuses.isEmpty()) {
|
||||
return;
|
||||
|
@ -140,25 +153,6 @@ public class TimelineAdapter extends RecyclerView.Adapter implements AdapterItem
|
|||
notifyItemRangeInserted(end, newStatuses.size());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeItem(int position) {
|
||||
statuses.remove(position);
|
||||
notifyItemRemoved(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeAllByAccountId(String accountId) {
|
||||
for (int i = 0; i < statuses.size();) {
|
||||
Status status = statuses.get(i);
|
||||
if (accountId.equals(status.account.id)) {
|
||||
statuses.remove(i);
|
||||
notifyItemRemoved(i);
|
||||
} else {
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
statuses.clear();
|
||||
notifyDataSetChanged();
|
||||
|
@ -171,4 +165,16 @@ public class TimelineAdapter extends RecyclerView.Adapter implements AdapterItem
|
|||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void setFooterState(FooterState newFooterState) {
|
||||
FooterState oldValue = footerState;
|
||||
footerState = newFooterState;
|
||||
if (footerState != oldValue) {
|
||||
notifyItemChanged(statuses.size());
|
||||
}
|
||||
}
|
||||
|
||||
public void setMediaPreviewEnabled(boolean enabled) {
|
||||
mediaPreviewEnabled = enabled;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue