Animate gif avatars (#1279)
* animate gif avatars * add setting to enable avatar animation * cleanup code
This commit is contained in:
parent
da1089184c
commit
83696b5c7f
40 changed files with 381 additions and 547 deletions
|
|
@ -16,19 +16,19 @@
|
|||
package com.keylesspalace.tusky.adapter
|
||||
|
||||
import android.content.Context
|
||||
import android.text.TextUtils
|
||||
import android.preference.PreferenceManager
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.ArrayAdapter
|
||||
import com.bumptech.glide.Glide
|
||||
import com.keylesspalace.tusky.R
|
||||
import com.keylesspalace.tusky.db.AccountEntity
|
||||
import com.keylesspalace.tusky.util.CustomEmojiHelper
|
||||
import com.keylesspalace.tusky.util.loadAvatar
|
||||
|
||||
import kotlinx.android.synthetic.main.item_autocomplete_account.view.*
|
||||
|
||||
class AccountSelectionAdapter(context: Context): ArrayAdapter<AccountEntity>(context, R.layout.item_autocomplete_account) {
|
||||
class AccountSelectionAdapter(context: Context) : ArrayAdapter<AccountEntity>(context, R.layout.item_autocomplete_account) {
|
||||
override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
|
||||
var view = convertView
|
||||
|
||||
|
|
@ -45,13 +45,13 @@ class AccountSelectionAdapter(context: Context): ArrayAdapter<AccountEntity>(con
|
|||
val avatar = view.avatar
|
||||
username.text = account.fullName
|
||||
displayName.text = CustomEmojiHelper.emojifyString(account.displayName, account.emojis, displayName)
|
||||
if (!TextUtils.isEmpty(account.profilePictureUrl)) {
|
||||
Glide.with(avatar)
|
||||
.asBitmap()
|
||||
.load(account.profilePictureUrl)
|
||||
.placeholder(R.drawable.avatar_default)
|
||||
.into(avatar)
|
||||
}
|
||||
|
||||
val avatarRadius = avatar.context.resources.getDimensionPixelSize(R.dimen.avatar_radius_42dp)
|
||||
val animateAvatar = PreferenceManager.getDefaultSharedPreferences(avatar.context)
|
||||
.getBoolean("animateGifAvatars", false)
|
||||
|
||||
loadAvatar(account.profilePictureUrl, avatar, avatarRadius, animateAvatar)
|
||||
|
||||
}
|
||||
|
||||
return view
|
||||
|
|
|
|||
|
|
@ -2,17 +2,18 @@ package com.keylesspalace.tusky.adapter;
|
|||
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import android.content.SharedPreferences;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.view.View;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.bumptech.glide.Glide;
|
||||
import com.keylesspalace.tusky.R;
|
||||
import com.keylesspalace.tusky.entity.Account;
|
||||
import com.keylesspalace.tusky.interfaces.AccountActionListener;
|
||||
import com.keylesspalace.tusky.interfaces.LinkListener;
|
||||
import com.keylesspalace.tusky.util.CustomEmojiHelper;
|
||||
import com.keylesspalace.tusky.util.ImageLoadingHelper;
|
||||
|
||||
class AccountViewHolder extends RecyclerView.ViewHolder {
|
||||
private TextView username;
|
||||
|
|
@ -21,6 +22,7 @@ class AccountViewHolder extends RecyclerView.ViewHolder {
|
|||
private ImageView avatarInset;
|
||||
private String accountId;
|
||||
private boolean showBotOverlay;
|
||||
private boolean animateAvatar;
|
||||
|
||||
AccountViewHolder(View itemView) {
|
||||
super(itemView);
|
||||
|
|
@ -28,7 +30,9 @@ class AccountViewHolder extends RecyclerView.ViewHolder {
|
|||
displayName = itemView.findViewById(R.id.account_display_name);
|
||||
avatar = itemView.findViewById(R.id.account_avatar);
|
||||
avatarInset = itemView.findViewById(R.id.account_avatar_inset);
|
||||
showBotOverlay = PreferenceManager.getDefaultSharedPreferences(itemView.getContext()).getBoolean("showBotOverlay", true);
|
||||
SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(itemView.getContext());
|
||||
showBotOverlay = sharedPrefs.getBoolean("showBotOverlay", true);
|
||||
animateAvatar = sharedPrefs.getBoolean("animateGifAvatars", false);
|
||||
}
|
||||
|
||||
void setupWithAccount(Account account) {
|
||||
|
|
@ -38,11 +42,9 @@ class AccountViewHolder extends RecyclerView.ViewHolder {
|
|||
username.setText(formattedUsername);
|
||||
CharSequence emojifiedName = CustomEmojiHelper.emojifyString(account.getName(), account.getEmojis(), displayName);
|
||||
displayName.setText(emojifiedName);
|
||||
Glide.with(avatar)
|
||||
.asBitmap()
|
||||
.load(account.getAvatar())
|
||||
.placeholder(R.drawable.avatar_default)
|
||||
.into(avatar);
|
||||
int avatarRadius = avatar.getContext().getResources()
|
||||
.getDimensionPixelSize(R.dimen.avatar_radius_48dp);
|
||||
ImageLoadingHelper.loadAvatar(account.getAvatar(), avatar, avatarRadius, animateAvatar);
|
||||
if (showBotOverlay && account.getBot()) {
|
||||
avatarInset.setVisibility(View.VISIBLE);
|
||||
avatarInset.setImageResource(R.drawable.ic_bot_24dp);
|
||||
|
|
|
|||
|
|
@ -17,6 +17,8 @@ package com.keylesspalace.tusky.adapter;
|
|||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import android.preference.PreferenceManager;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
|
@ -24,11 +26,11 @@ import android.widget.ImageButton;
|
|||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.bumptech.glide.Glide;
|
||||
import com.keylesspalace.tusky.R;
|
||||
import com.keylesspalace.tusky.entity.Account;
|
||||
import com.keylesspalace.tusky.interfaces.AccountActionListener;
|
||||
import com.keylesspalace.tusky.util.CustomEmojiHelper;
|
||||
import com.keylesspalace.tusky.util.ImageLoadingHelper;
|
||||
|
||||
public class BlocksAdapter extends AccountAdapter {
|
||||
|
||||
|
|
@ -69,6 +71,7 @@ public class BlocksAdapter extends AccountAdapter {
|
|||
private TextView displayName;
|
||||
private ImageButton unblock;
|
||||
private String id;
|
||||
private boolean animateAvatar;
|
||||
|
||||
BlockedUserViewHolder(View itemView) {
|
||||
super(itemView);
|
||||
|
|
@ -76,6 +79,9 @@ public class BlocksAdapter extends AccountAdapter {
|
|||
username = itemView.findViewById(R.id.blocked_user_username);
|
||||
displayName = itemView.findViewById(R.id.blocked_user_display_name);
|
||||
unblock = itemView.findViewById(R.id.blocked_user_unblock);
|
||||
animateAvatar = PreferenceManager.getDefaultSharedPreferences(itemView.getContext())
|
||||
.getBoolean("animateGifAvatars", false);
|
||||
|
||||
}
|
||||
|
||||
void setupWithAccount(Account account) {
|
||||
|
|
@ -85,11 +91,9 @@ public class BlocksAdapter extends AccountAdapter {
|
|||
String format = username.getContext().getString(R.string.status_username_format);
|
||||
String formattedUsername = String.format(format, account.getUsername());
|
||||
username.setText(formattedUsername);
|
||||
Glide.with(avatar)
|
||||
.asBitmap()
|
||||
.load(account.getAvatar())
|
||||
.placeholder(R.drawable.avatar_default)
|
||||
.into(avatar);
|
||||
int avatarRadius = avatar.getContext().getResources()
|
||||
.getDimensionPixelSize(R.dimen.avatar_radius_48dp);
|
||||
ImageLoadingHelper.loadAvatar(account.getAvatar(), avatar, avatarRadius, animateAvatar);
|
||||
}
|
||||
|
||||
void setupActionListener(final AccountActionListener listener) {
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
package com.keylesspalace.tusky.adapter;
|
||||
|
||||
import android.content.Context;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
|
@ -30,6 +31,7 @@ import com.keylesspalace.tusky.R;
|
|||
import com.keylesspalace.tusky.entity.Account;
|
||||
import com.keylesspalace.tusky.entity.Emoji;
|
||||
import com.keylesspalace.tusky.util.CustomEmojiHelper;
|
||||
import com.keylesspalace.tusky.util.ImageLoadingHelper;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
|
@ -146,13 +148,19 @@ public class ComposeAutoCompleteAdapter extends BaseAdapter
|
|||
CharSequence emojifiedName = CustomEmojiHelper.emojifyString(account.getName(),
|
||||
account.getEmojis(), accountViewHolder.displayName);
|
||||
accountViewHolder.displayName.setText(emojifiedName);
|
||||
if (!account.getAvatar().isEmpty()) {
|
||||
Glide.with(accountViewHolder.avatar)
|
||||
.asBitmap()
|
||||
.load(account.getAvatar())
|
||||
.placeholder(R.drawable.avatar_default)
|
||||
.into(accountViewHolder.avatar);
|
||||
}
|
||||
|
||||
int avatarRadius = accountViewHolder.avatar.getContext().getResources()
|
||||
.getDimensionPixelSize(R.dimen.avatar_radius_42dp);
|
||||
|
||||
boolean animateAvatar = PreferenceManager.getDefaultSharedPreferences(accountViewHolder.avatar.getContext())
|
||||
.getBoolean("animateGifAvatars", false);
|
||||
|
||||
ImageLoadingHelper.loadAvatar(
|
||||
account.getAvatar(),
|
||||
accountViewHolder.avatar,
|
||||
avatarRadius,
|
||||
animateAvatar
|
||||
);
|
||||
}
|
||||
break;
|
||||
|
||||
|
|
|
|||
|
|
@ -17,6 +17,8 @@ package com.keylesspalace.tusky.adapter;
|
|||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import android.preference.PreferenceManager;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
|
@ -24,11 +26,11 @@ import android.widget.ImageButton;
|
|||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.bumptech.glide.Glide;
|
||||
import com.keylesspalace.tusky.R;
|
||||
import com.keylesspalace.tusky.entity.Account;
|
||||
import com.keylesspalace.tusky.interfaces.AccountActionListener;
|
||||
import com.keylesspalace.tusky.util.CustomEmojiHelper;
|
||||
import com.keylesspalace.tusky.util.ImageLoadingHelper;
|
||||
|
||||
public class FollowRequestsAdapter extends AccountAdapter {
|
||||
|
||||
|
|
@ -70,6 +72,7 @@ public class FollowRequestsAdapter extends AccountAdapter {
|
|||
private ImageButton accept;
|
||||
private ImageButton reject;
|
||||
private String id;
|
||||
private boolean animateAvatar;
|
||||
|
||||
FollowRequestViewHolder(View itemView) {
|
||||
super(itemView);
|
||||
|
|
@ -78,6 +81,8 @@ public class FollowRequestsAdapter extends AccountAdapter {
|
|||
displayName = itemView.findViewById(R.id.displayNameTextView);
|
||||
accept = itemView.findViewById(R.id.acceptButton);
|
||||
reject = itemView.findViewById(R.id.rejectButton);
|
||||
animateAvatar = PreferenceManager.getDefaultSharedPreferences(itemView.getContext())
|
||||
.getBoolean("animateGifAvatars", false);
|
||||
}
|
||||
|
||||
void setupWithAccount(Account account) {
|
||||
|
|
@ -87,11 +92,9 @@ public class FollowRequestsAdapter extends AccountAdapter {
|
|||
String format = username.getContext().getString(R.string.status_username_format);
|
||||
String formattedUsername = String.format(format, account.getUsername());
|
||||
username.setText(formattedUsername);
|
||||
Glide.with(avatar)
|
||||
.asBitmap()
|
||||
.load(account.getAvatar())
|
||||
.placeholder(R.drawable.avatar_default)
|
||||
.into(avatar);
|
||||
int avatarRadius = avatar.getContext().getResources()
|
||||
.getDimensionPixelSize(R.dimen.avatar_radius_48dp);
|
||||
ImageLoadingHelper.loadAvatar(account.getAvatar(), avatar, avatarRadius, animateAvatar);
|
||||
}
|
||||
|
||||
void setupActionListener(final AccountActionListener listener) {
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@ package com.keylesspalace.tusky.adapter;
|
|||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import android.preference.PreferenceManager;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
|
@ -9,11 +11,11 @@ import android.widget.ImageButton;
|
|||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.bumptech.glide.Glide;
|
||||
import com.keylesspalace.tusky.R;
|
||||
import com.keylesspalace.tusky.entity.Account;
|
||||
import com.keylesspalace.tusky.interfaces.AccountActionListener;
|
||||
import com.keylesspalace.tusky.util.CustomEmojiHelper;
|
||||
import com.keylesspalace.tusky.util.ImageLoadingHelper;
|
||||
|
||||
public class MutesAdapter extends AccountAdapter {
|
||||
|
||||
|
|
@ -55,6 +57,7 @@ public class MutesAdapter extends AccountAdapter {
|
|||
private TextView displayName;
|
||||
private ImageButton unmute;
|
||||
private String id;
|
||||
private boolean animateAvatar;
|
||||
|
||||
MutedUserViewHolder(View itemView) {
|
||||
super(itemView);
|
||||
|
|
@ -62,6 +65,8 @@ public class MutesAdapter extends AccountAdapter {
|
|||
username = itemView.findViewById(R.id.muted_user_username);
|
||||
displayName = itemView.findViewById(R.id.muted_user_display_name);
|
||||
unmute = itemView.findViewById(R.id.muted_user_unmute);
|
||||
animateAvatar = PreferenceManager.getDefaultSharedPreferences(itemView.getContext())
|
||||
.getBoolean("animateGifAvatars", false);
|
||||
}
|
||||
|
||||
void setupWithAccount(Account account) {
|
||||
|
|
@ -71,11 +76,9 @@ public class MutesAdapter extends AccountAdapter {
|
|||
String format = username.getContext().getString(R.string.status_username_format);
|
||||
String formattedUsername = String.format(format, account.getUsername());
|
||||
username.setText(formattedUsername);
|
||||
Glide.with(avatar)
|
||||
.asBitmap()
|
||||
.load(account.getAvatar())
|
||||
.placeholder(R.drawable.avatar_default)
|
||||
.into(avatar);
|
||||
int avatarRadius = avatar.getContext().getResources()
|
||||
.getDimensionPixelSize(R.dimen.avatar_radius_48dp);
|
||||
ImageLoadingHelper.loadAvatar(account.getAvatar(), avatar, avatarRadius, animateAvatar);
|
||||
}
|
||||
|
||||
void setupActionListener(final AccountActionListener listener) {
|
||||
|
|
|
|||
|
|
@ -33,7 +33,6 @@ import android.widget.ImageView;
|
|||
import android.widget.TextView;
|
||||
import android.widget.ToggleButton;
|
||||
|
||||
import com.bumptech.glide.Glide;
|
||||
import com.keylesspalace.tusky.R;
|
||||
import com.keylesspalace.tusky.entity.Account;
|
||||
import com.keylesspalace.tusky.entity.Emoji;
|
||||
|
|
@ -42,6 +41,7 @@ import com.keylesspalace.tusky.interfaces.LinkListener;
|
|||
import com.keylesspalace.tusky.interfaces.StatusActionListener;
|
||||
import com.keylesspalace.tusky.util.CustomEmojiHelper;
|
||||
import com.keylesspalace.tusky.util.DateUtils;
|
||||
import com.keylesspalace.tusky.util.ImageLoadingHelper;
|
||||
import com.keylesspalace.tusky.util.LinkHelper;
|
||||
import com.keylesspalace.tusky.util.SmartLengthInputFilter;
|
||||
import com.keylesspalace.tusky.viewdata.NotificationViewData;
|
||||
|
|
@ -82,6 +82,8 @@ public class NotificationsAdapter extends RecyclerView.Adapter {
|
|||
private NotificationActionListener notificationActionListener;
|
||||
private boolean mediaPreviewEnabled;
|
||||
private boolean useAbsoluteTime;
|
||||
private boolean showBotOverlay;
|
||||
private boolean animateAvatar;
|
||||
private BidiFormatter bidiFormatter;
|
||||
private AdapterDataSource<NotificationViewData> dataSource;
|
||||
|
||||
|
|
@ -96,6 +98,8 @@ public class NotificationsAdapter extends RecyclerView.Adapter {
|
|||
this.notificationActionListener = notificationActionListener;
|
||||
mediaPreviewEnabled = true;
|
||||
useAbsoluteTime = false;
|
||||
showBotOverlay = true;
|
||||
animateAvatar = false;
|
||||
bidiFormatter = BidiFormatter.getInstance();
|
||||
}
|
||||
|
||||
|
|
@ -112,12 +116,12 @@ public class NotificationsAdapter extends RecyclerView.Adapter {
|
|||
case VIEW_TYPE_STATUS_NOTIFICATION: {
|
||||
View view = inflater
|
||||
.inflate(R.layout.item_status_notification, parent, false);
|
||||
return new StatusNotificationViewHolder(view, useAbsoluteTime);
|
||||
return new StatusNotificationViewHolder(view, useAbsoluteTime, animateAvatar);
|
||||
}
|
||||
case VIEW_TYPE_FOLLOW: {
|
||||
View view = inflater
|
||||
.inflate(R.layout.item_follow, parent, false);
|
||||
return new FollowViewHolder(view);
|
||||
return new FollowViewHolder(view, animateAvatar);
|
||||
}
|
||||
case VIEW_TYPE_PLACEHOLDER: {
|
||||
View view = inflater
|
||||
|
|
@ -167,7 +171,7 @@ public class NotificationsAdapter extends RecyclerView.Adapter {
|
|||
StatusViewHolder holder = (StatusViewHolder) viewHolder;
|
||||
StatusViewData.Concrete status = concreteNotificaton.getStatusViewData();
|
||||
holder.setupWithStatus(status,
|
||||
statusListener, mediaPreviewEnabled, payloadForHolder);
|
||||
statusListener, mediaPreviewEnabled, showBotOverlay, animateAvatar, payloadForHolder);
|
||||
if(concreteNotificaton.getType() == Notification.Type.POLL) {
|
||||
holder.setPollInfo(accountId.equals(concreteNotificaton.getAccount().getId()));
|
||||
} else {
|
||||
|
|
@ -266,6 +270,14 @@ public class NotificationsAdapter extends RecyclerView.Adapter {
|
|||
this.useAbsoluteTime = useAbsoluteTime;
|
||||
}
|
||||
|
||||
public void setShowBotOverlay(boolean showBotOverlay) {
|
||||
this.showBotOverlay = showBotOverlay;
|
||||
}
|
||||
|
||||
public void setAnimateAvatar(boolean animateAvatar) {
|
||||
this.animateAvatar = animateAvatar;
|
||||
}
|
||||
|
||||
public interface NotificationActionListener {
|
||||
void onViewAccount(String id);
|
||||
|
||||
|
|
@ -288,13 +300,15 @@ public class NotificationsAdapter extends RecyclerView.Adapter {
|
|||
private TextView usernameView;
|
||||
private TextView displayNameView;
|
||||
private ImageView avatar;
|
||||
private boolean animateAvatar;
|
||||
|
||||
FollowViewHolder(View itemView) {
|
||||
FollowViewHolder(View itemView, boolean animateAvatar) {
|
||||
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;
|
||||
}
|
||||
|
||||
void setMessage(Account account, BidiFormatter bidiFormatter) {
|
||||
|
|
@ -313,15 +327,11 @@ public class NotificationsAdapter extends RecyclerView.Adapter {
|
|||
|
||||
displayNameView.setText(emojifiedDisplayName);
|
||||
|
||||
if (TextUtils.isEmpty(account.getAvatar())) {
|
||||
avatar.setImageResource(R.drawable.avatar_default);
|
||||
} else {
|
||||
Glide.with(avatar)
|
||||
.asBitmap()
|
||||
.load(account.getAvatar())
|
||||
.placeholder(R.drawable.avatar_default)
|
||||
.into(avatar);
|
||||
}
|
||||
int avatarRadius = avatar.getContext().getResources()
|
||||
.getDimensionPixelSize(R.dimen.avatar_radius_24dp);
|
||||
|
||||
ImageLoadingHelper.loadAvatar(account.getAvatar(), avatar, avatarRadius, animateAvatar);
|
||||
|
||||
}
|
||||
|
||||
void setupButtons(final NotificationActionListener listener, final String accountId) {
|
||||
|
|
@ -349,10 +359,11 @@ public class NotificationsAdapter extends RecyclerView.Adapter {
|
|||
private StatusViewData.Concrete statusViewData;
|
||||
|
||||
private boolean useAbsoluteTime;
|
||||
private boolean animateAvatar;
|
||||
private SimpleDateFormat shortSdf;
|
||||
private SimpleDateFormat longSdf;
|
||||
|
||||
StatusNotificationViewHolder(View itemView, boolean useAbsoluteTime) {
|
||||
StatusNotificationViewHolder(View itemView, boolean useAbsoluteTime, boolean animateAvatar) {
|
||||
super(itemView);
|
||||
message = itemView.findViewById(R.id.notification_top_text);
|
||||
statusNameBar = itemView.findViewById(R.id.status_name_bar);
|
||||
|
|
@ -376,6 +387,7 @@ public class NotificationsAdapter extends RecyclerView.Adapter {
|
|||
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());
|
||||
}
|
||||
|
|
@ -495,23 +507,17 @@ public class NotificationsAdapter extends RecyclerView.Adapter {
|
|||
|
||||
void setAvatars(@Nullable String statusAvatarUrl, @Nullable String notificationAvatarUrl) {
|
||||
|
||||
if (TextUtils.isEmpty(statusAvatarUrl)) {
|
||||
statusAvatar.setImageResource(R.drawable.avatar_default);
|
||||
} else {
|
||||
Glide.with(statusAvatar)
|
||||
.load(statusAvatarUrl)
|
||||
.placeholder(R.drawable.avatar_default)
|
||||
.into(statusAvatar);
|
||||
}
|
||||
int statusAvatarRadius = statusAvatar.getContext().getResources()
|
||||
.getDimensionPixelSize(R.dimen.avatar_radius_48dp);
|
||||
|
||||
if (TextUtils.isEmpty(notificationAvatarUrl)) {
|
||||
notificationAvatar.setImageResource(R.drawable.avatar_default);
|
||||
} else {
|
||||
Glide.with(notificationAvatar)
|
||||
.load(notificationAvatarUrl)
|
||||
.placeholder(R.drawable.avatar_default)
|
||||
.into(notificationAvatar);
|
||||
}
|
||||
ImageLoadingHelper.loadAvatar(statusAvatarUrl,
|
||||
statusAvatar, statusAvatarRadius, animateAvatar);
|
||||
|
||||
int notificationAvatarRadius = statusAvatar.getContext().getResources()
|
||||
.getDimensionPixelSize(R.dimen.avatar_radius_24dp);
|
||||
|
||||
ImageLoadingHelper.loadAvatar(notificationAvatarUrl,
|
||||
notificationAvatar, notificationAvatarRadius, animateAvatar);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -49,15 +49,19 @@ public class SearchResultsAdapter extends RecyclerView.Adapter {
|
|||
private boolean mediaPreviewsEnabled;
|
||||
private boolean alwaysShowSensitiveMedia;
|
||||
private boolean useAbsoluteTime;
|
||||
private boolean showBotOverlay;
|
||||
private boolean animateAvatar;
|
||||
|
||||
private LinkListener linkListener;
|
||||
private StatusActionListener statusListener;
|
||||
|
||||
public SearchResultsAdapter(boolean mediaPreviewsEnabled,
|
||||
boolean alwaysShowSensitiveMedia,
|
||||
LinkListener linkListener,
|
||||
public SearchResultsAdapter(LinkListener linkListener,
|
||||
StatusActionListener statusListener,
|
||||
boolean useAbsoluteTime) {
|
||||
boolean mediaPreviewsEnabled,
|
||||
boolean alwaysShowSensitiveMedia,
|
||||
boolean useAbsoluteTime,
|
||||
boolean showBotOverlay,
|
||||
boolean animateAvatar) {
|
||||
|
||||
this.accountList = Collections.emptyList();
|
||||
this.statusList = Collections.emptyList();
|
||||
|
|
@ -67,6 +71,8 @@ public class SearchResultsAdapter extends RecyclerView.Adapter {
|
|||
this.mediaPreviewsEnabled = mediaPreviewsEnabled;
|
||||
this.alwaysShowSensitiveMedia = alwaysShowSensitiveMedia;
|
||||
this.useAbsoluteTime = useAbsoluteTime;
|
||||
this.showBotOverlay = showBotOverlay;
|
||||
this.animateAvatar = animateAvatar;
|
||||
|
||||
this.linkListener = linkListener;
|
||||
this.statusListener = statusListener;
|
||||
|
|
@ -98,22 +104,23 @@ public class SearchResultsAdapter extends RecyclerView.Adapter {
|
|||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, int position) {
|
||||
if (position >= accountList.size()) {
|
||||
if(position >= accountList.size() + concreteStatusList.size()) {
|
||||
HashtagViewHolder holder = (HashtagViewHolder) viewHolder;
|
||||
int index = position - accountList.size() - concreteStatusList.size();
|
||||
holder.setup(hashtagList.get(index), linkListener);
|
||||
} else {
|
||||
StatusViewHolder holder = (StatusViewHolder) viewHolder;
|
||||
int index = position - accountList.size();
|
||||
holder.setupWithStatus(concreteStatusList.get(index), statusListener, mediaPreviewsEnabled);
|
||||
}
|
||||
if (position >= accountList.size()) {
|
||||
if(position >= accountList.size() + concreteStatusList.size()) {
|
||||
HashtagViewHolder holder = (HashtagViewHolder) viewHolder;
|
||||
int index = position - accountList.size() - concreteStatusList.size();
|
||||
holder.setup(hashtagList.get(index), linkListener);
|
||||
} else {
|
||||
AccountViewHolder holder = (AccountViewHolder) viewHolder;
|
||||
holder.setupWithAccount(accountList.get(position));
|
||||
holder.setupLinkListener(linkListener);
|
||||
StatusViewHolder holder = (StatusViewHolder) viewHolder;
|
||||
int index = position - accountList.size();
|
||||
holder.setupWithStatus(concreteStatusList.get(index), statusListener,
|
||||
mediaPreviewsEnabled, showBotOverlay, animateAvatar);
|
||||
}
|
||||
} else {
|
||||
AccountViewHolder holder = (AccountViewHolder) viewHolder;
|
||||
holder.setupWithAccount(accountList.get(position));
|
||||
holder.setupLinkListener(linkListener);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
|
|
@ -133,11 +140,11 @@ public class SearchResultsAdapter extends RecyclerView.Adapter {
|
|||
}
|
||||
}
|
||||
|
||||
public @Nullable Status getStatusAtPosition(int position) {
|
||||
@Nullable public Status getStatusAtPosition(int position) {
|
||||
return statusList.get(position - accountList.size());
|
||||
}
|
||||
|
||||
public @Nullable StatusViewData.Concrete getConcreteStatusAtPosition(int position) {
|
||||
@Nullable public StatusViewData.Concrete getConcreteStatusAtPosition(int position) {
|
||||
return concreteStatusList.get(position - accountList.size());
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ package com.keylesspalace.tusky.adapter;
|
|||
|
||||
import android.content.Context;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.text.Spanned;
|
||||
import android.text.TextUtils;
|
||||
import android.view.View;
|
||||
|
|
@ -16,6 +15,13 @@ import android.widget.RadioGroup;
|
|||
import android.widget.TextView;
|
||||
import android.widget.ToggleButton;
|
||||
|
||||
import androidx.annotation.DrawableRes;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.content.res.AppCompatResources;
|
||||
import androidx.emoji.text.EmojiCompat;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.bumptech.glide.Glide;
|
||||
import com.keylesspalace.tusky.R;
|
||||
import com.keylesspalace.tusky.entity.Attachment;
|
||||
|
|
@ -29,6 +35,7 @@ import com.keylesspalace.tusky.interfaces.StatusActionListener;
|
|||
import com.keylesspalace.tusky.util.CustomEmojiHelper;
|
||||
import com.keylesspalace.tusky.util.DateUtils;
|
||||
import com.keylesspalace.tusky.util.HtmlUtils;
|
||||
import com.keylesspalace.tusky.util.ImageLoadingHelper;
|
||||
import com.keylesspalace.tusky.util.LinkHelper;
|
||||
import com.keylesspalace.tusky.util.ThemeUtils;
|
||||
import com.keylesspalace.tusky.view.MediaPreviewImageView;
|
||||
|
|
@ -43,12 +50,6 @@ import java.util.Date;
|
|||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import androidx.annotation.DrawableRes;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.content.res.AppCompatResources;
|
||||
import androidx.emoji.text.EmojiCompat;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import at.connyduck.sparkbutton.SparkButton;
|
||||
import at.connyduck.sparkbutton.SparkEventListener;
|
||||
import kotlin.collections.CollectionsKt;
|
||||
|
|
@ -89,11 +90,15 @@ public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder {
|
|||
private boolean useAbsoluteTime;
|
||||
private SimpleDateFormat shortSdf;
|
||||
private SimpleDateFormat longSdf;
|
||||
private boolean showBotOverlay;
|
||||
|
||||
private final NumberFormat numberFormat = NumberFormat.getNumberInstance();
|
||||
|
||||
protected StatusBaseViewHolder(View itemView, boolean useAbsoluteTime) {
|
||||
private int avatarRadius48dp;
|
||||
private int avatarRadius36dp;
|
||||
private int avatarRadius24dp;
|
||||
|
||||
protected StatusBaseViewHolder(View itemView,
|
||||
boolean useAbsoluteTime) {
|
||||
super(itemView);
|
||||
displayName = itemView.findViewById(R.id.status_display_name);
|
||||
username = itemView.findViewById(R.id.status_username);
|
||||
|
|
@ -104,8 +109,7 @@ public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder {
|
|||
reblogButton = itemView.findViewById(R.id.status_inset);
|
||||
favouriteButton = itemView.findViewById(R.id.status_favourite);
|
||||
moreButton = itemView.findViewById(R.id.status_more);
|
||||
reblogged = false;
|
||||
favourited = false;
|
||||
|
||||
mediaPreviews = new MediaPreviewImageView[]{
|
||||
itemView.findViewById(R.id.status_media_preview_0),
|
||||
itemView.findViewById(R.id.status_media_preview_1),
|
||||
|
|
@ -153,7 +157,10 @@ public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder {
|
|||
this.useAbsoluteTime = useAbsoluteTime;
|
||||
shortSdf = new SimpleDateFormat("HH:mm:ss", Locale.getDefault());
|
||||
longSdf = new SimpleDateFormat("MM/dd HH:mm:ss", Locale.getDefault());
|
||||
showBotOverlay = PreferenceManager.getDefaultSharedPreferences(itemView.getContext()).getBoolean("showBotOverlay", true);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
protected abstract int getMediaPreviewHeight(Context context);
|
||||
|
|
@ -219,8 +226,13 @@ public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder {
|
|||
}
|
||||
}
|
||||
|
||||
private void setAvatar(String url, @Nullable String rebloggedUrl, boolean isBot) {
|
||||
private void setAvatar(String url,
|
||||
@Nullable String rebloggedUrl,
|
||||
boolean isBot,
|
||||
boolean showBotOverlay,
|
||||
boolean animateAvatar) {
|
||||
|
||||
int avatarRadius;
|
||||
if(TextUtils.isEmpty(rebloggedUrl)) {
|
||||
avatar.setPaddingRelative(0, 0, 0, 0);
|
||||
|
||||
|
|
@ -235,28 +247,20 @@ public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder {
|
|||
avatarInset.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
avatarRadius = avatarRadius48dp;
|
||||
|
||||
} else {
|
||||
int padding = Utils.convertDpToPx(avatar.getContext(), 12);
|
||||
avatar.setPaddingRelative(0, 0, padding, padding);
|
||||
|
||||
avatarInset.setVisibility(View.VISIBLE);
|
||||
avatarInset.setBackground(null);
|
||||
Glide.with(avatarInset)
|
||||
.asBitmap()
|
||||
.load(rebloggedUrl)
|
||||
.placeholder(R.drawable.avatar_default)
|
||||
.into(avatarInset);
|
||||
ImageLoadingHelper.loadAvatar(rebloggedUrl, avatarInset, avatarRadius24dp, animateAvatar);
|
||||
|
||||
avatarRadius = avatarRadius36dp;
|
||||
}
|
||||
|
||||
if (TextUtils.isEmpty(url)) {
|
||||
avatar.setImageResource(R.drawable.avatar_default);
|
||||
} else {
|
||||
Glide.with(avatar)
|
||||
.asBitmap()
|
||||
.load(url)
|
||||
.placeholder(R.drawable.avatar_default)
|
||||
.into(avatar);
|
||||
}
|
||||
ImageLoadingHelper.loadAvatar(url, avatar, avatarRadius, animateAvatar);
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -610,18 +614,22 @@ public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder {
|
|||
}
|
||||
|
||||
protected void setupWithStatus(StatusViewData.Concrete status, final StatusActionListener listener,
|
||||
boolean mediaPreviewEnabled) {
|
||||
this.setupWithStatus(status, listener, mediaPreviewEnabled, null);
|
||||
boolean mediaPreviewEnabled, boolean showBotOverlay, boolean animateAvatar) {
|
||||
this.setupWithStatus(status, listener, mediaPreviewEnabled, showBotOverlay, animateAvatar, null);
|
||||
}
|
||||
|
||||
protected void setupWithStatus(StatusViewData.Concrete status, final StatusActionListener listener,
|
||||
boolean mediaPreviewEnabled, @Nullable Object payloads) {
|
||||
protected void setupWithStatus(StatusViewData.Concrete status,
|
||||
final StatusActionListener listener,
|
||||
boolean mediaPreviewEnabled,
|
||||
boolean showBotOverlay,
|
||||
boolean animateAvatar,
|
||||
@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());
|
||||
setAvatar(status.getAvatar(), status.getRebloggedAvatar(), status.isBot(), showBotOverlay, animateAvatar);
|
||||
setReblogged(status.isReblogged());
|
||||
setFavourited(status.isFavourited());
|
||||
List<Attachment> attachments = status.getAttachments();
|
||||
|
|
|
|||
|
|
@ -125,8 +125,9 @@ class StatusDetailedViewHolder extends StatusBaseViewHolder {
|
|||
|
||||
@Override
|
||||
protected void setupWithStatus(final StatusViewData.Concrete status, final StatusActionListener listener,
|
||||
boolean mediaPreviewEnabled, @Nullable Object payloads) {
|
||||
super.setupWithStatus(status, listener, mediaPreviewEnabled, payloads);
|
||||
boolean mediaPreviewEnabled, boolean showBotOverlay, boolean animateAvatar,
|
||||
@Nullable Object payloads) {
|
||||
super.setupWithStatus(status, listener, mediaPreviewEnabled, showBotOverlay, animateAvatar, payloads);
|
||||
if (payloads == null) {
|
||||
setReblogAndFavCount(status.getReblogsCount(), status.getFavouritesCount(), listener);
|
||||
|
||||
|
|
|
|||
|
|
@ -51,14 +51,15 @@ public class StatusViewHolder extends StatusBaseViewHolder {
|
|||
|
||||
@Override
|
||||
protected void setupWithStatus(StatusViewData.Concrete status, final StatusActionListener listener,
|
||||
boolean mediaPreviewEnabled, @Nullable Object payloads) {
|
||||
boolean mediaPreviewEnabled, boolean showBotOverlay, boolean animateAvatar,
|
||||
@Nullable Object payloads) {
|
||||
if (status == null || payloads == null) {
|
||||
if (status == null) {
|
||||
showContent(false);
|
||||
} else {
|
||||
showContent(true);
|
||||
setupCollapsedState(status, listener);
|
||||
super.setupWithStatus(status, listener, mediaPreviewEnabled, null);
|
||||
super.setupWithStatus(status, listener, mediaPreviewEnabled, showBotOverlay, animateAvatar, null);
|
||||
|
||||
String rebloggedByDisplayName = status.getRebloggedByUsername();
|
||||
if (rebloggedByDisplayName == null) {
|
||||
|
|
@ -70,7 +71,7 @@ public class StatusViewHolder extends StatusBaseViewHolder {
|
|||
|
||||
}
|
||||
} else {
|
||||
super.setupWithStatus(status, listener, mediaPreviewEnabled, payloads);
|
||||
super.setupWithStatus(status, listener, mediaPreviewEnabled, showBotOverlay, animateAvatar, payloads);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -37,6 +37,8 @@ public class ThreadAdapter extends RecyclerView.Adapter {
|
|||
private StatusActionListener statusActionListener;
|
||||
private boolean mediaPreviewEnabled;
|
||||
private boolean useAbsoluteTime;
|
||||
private boolean showBotOverlay;
|
||||
private boolean animateAvatar;
|
||||
private int detailedStatusPosition;
|
||||
|
||||
public ThreadAdapter(StatusActionListener listener) {
|
||||
|
|
@ -44,6 +46,8 @@ public class ThreadAdapter extends RecyclerView.Adapter {
|
|||
this.statuses = new ArrayList<>();
|
||||
mediaPreviewEnabled = true;
|
||||
useAbsoluteTime = false;
|
||||
showBotOverlay = true;
|
||||
animateAvatar = false;
|
||||
detailedStatusPosition = RecyclerView.NO_POSITION;
|
||||
}
|
||||
|
||||
|
|
@ -70,10 +74,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);
|
||||
holder.setupWithStatus(status, statusActionListener, mediaPreviewEnabled, showBotOverlay, animateAvatar);
|
||||
} else {
|
||||
StatusViewHolder holder = (StatusViewHolder) viewHolder;
|
||||
holder.setupWithStatus(status, statusActionListener, mediaPreviewEnabled);
|
||||
holder.setupWithStatus(status, statusActionListener, mediaPreviewEnabled, showBotOverlay, animateAvatar);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -155,6 +159,14 @@ public class ThreadAdapter extends RecyclerView.Adapter {
|
|||
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) {
|
||||
|
|
|
|||
|
|
@ -43,14 +43,17 @@ public final class TimelineAdapter extends RecyclerView.Adapter {
|
|||
private final StatusActionListener statusListener;
|
||||
private boolean mediaPreviewEnabled;
|
||||
private boolean useAbsoluteTime;
|
||||
private boolean showBotOverlay;
|
||||
private boolean animateAvatar;
|
||||
|
||||
public TimelineAdapter(AdapterDataSource<StatusViewData> dataSource,
|
||||
StatusActionListener statusListener) {
|
||||
super();
|
||||
this.dataSource = dataSource;
|
||||
this.statusListener = statusListener;
|
||||
mediaPreviewEnabled = true;
|
||||
useAbsoluteTime = false;
|
||||
showBotOverlay = true;
|
||||
animateAvatar = false;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
|
|
@ -89,7 +92,12 @@ public final class TimelineAdapter extends RecyclerView.Adapter {
|
|||
holder.setup(statusListener, ((StatusViewData.Placeholder) status).isLoading());
|
||||
} else if (status instanceof StatusViewData.Concrete) {
|
||||
StatusViewHolder holder = (StatusViewHolder) viewHolder;
|
||||
holder.setupWithStatus((StatusViewData.Concrete)status,statusListener, mediaPreviewEnabled,payloads!=null&&!payloads.isEmpty()?payloads.get(0):null);
|
||||
holder.setupWithStatus((StatusViewData.Concrete) status,
|
||||
statusListener,
|
||||
mediaPreviewEnabled,
|
||||
showBotOverlay,
|
||||
animateAvatar,
|
||||
payloads != null && !payloads.isEmpty() ? payloads.get(0) : null);
|
||||
}
|
||||
}
|
||||
@Override
|
||||
|
|
@ -111,13 +119,21 @@ public final class TimelineAdapter extends RecyclerView.Adapter {
|
|||
}
|
||||
|
||||
public void setUseAbsoluteTime(boolean useAbsoluteTime){
|
||||
this.useAbsoluteTime=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