Convert AccountViewHolder from Java to Kotlin (#3044)
* Convert AccountViewHolder from Java to Kotlin Use view binding in the converted code, which requires small changes in code that calls constructors. Pass showBotOverlays as a parameter, rather than having the code reach in to the shared preferences, fixing a layering violation. This affects callers and classes derived from AccountAdapter. * Use 2-arg getString * Simplify setting bot badge indicator - Specify the drawable in the XML - Use visible() to set visibility - Rename ID to account_bot_badge to make it clearer that this is all it is for * Use lateinit to avoid needing !! later
This commit is contained in:
parent
a21f2fadf9
commit
ee765a3117
13 changed files with 116 additions and 91 deletions
|
@ -26,7 +26,8 @@ import com.keylesspalace.tusky.util.removeDuplicates
|
|||
abstract class AccountAdapter<AVH : RecyclerView.ViewHolder> internal constructor(
|
||||
var accountActionListener: AccountActionListener,
|
||||
protected val animateAvatar: Boolean,
|
||||
protected val animateEmojis: Boolean
|
||||
protected val animateEmojis: Boolean,
|
||||
protected val showBotOverlay: Boolean
|
||||
) : RecyclerView.Adapter<RecyclerView.ViewHolder?>() {
|
||||
var accountList = mutableListOf<TimelineAccount>()
|
||||
private var bottomLoading: Boolean = false
|
||||
|
|
|
@ -1,61 +0,0 @@
|
|||
package com.keylesspalace.tusky.adapter;
|
||||
|
||||
import android.content.SharedPreferences;
|
||||
import android.view.View;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.preference.PreferenceManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.keylesspalace.tusky.R;
|
||||
import com.keylesspalace.tusky.entity.TimelineAccount;
|
||||
import com.keylesspalace.tusky.interfaces.AccountActionListener;
|
||||
import com.keylesspalace.tusky.interfaces.LinkListener;
|
||||
import com.keylesspalace.tusky.util.CustomEmojiHelper;
|
||||
import com.keylesspalace.tusky.util.ImageLoadingHelper;
|
||||
|
||||
public class AccountViewHolder extends RecyclerView.ViewHolder {
|
||||
private TextView username;
|
||||
private TextView displayName;
|
||||
private ImageView avatar;
|
||||
private ImageView avatarInset;
|
||||
private String accountId;
|
||||
private boolean showBotOverlay;
|
||||
|
||||
public AccountViewHolder(View itemView) {
|
||||
super(itemView);
|
||||
username = itemView.findViewById(R.id.account_username);
|
||||
displayName = itemView.findViewById(R.id.account_display_name);
|
||||
avatar = itemView.findViewById(R.id.account_avatar);
|
||||
avatarInset = itemView.findViewById(R.id.account_avatar_inset);
|
||||
SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(itemView.getContext());
|
||||
showBotOverlay = sharedPrefs.getBoolean("showBotOverlay", true);
|
||||
}
|
||||
|
||||
public void setupWithAccount(TimelineAccount account, boolean animateAvatar, boolean animateEmojis) {
|
||||
accountId = account.getId();
|
||||
String format = username.getContext().getString(R.string.post_username_format);
|
||||
String formattedUsername = String.format(format, account.getUsername());
|
||||
username.setText(formattedUsername);
|
||||
CharSequence emojifiedName = CustomEmojiHelper.emojify(account.getName(), account.getEmojis(), displayName, animateEmojis);
|
||||
displayName.setText(emojifiedName);
|
||||
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.bot_badge);
|
||||
} else {
|
||||
avatarInset.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
|
||||
void setupActionListener(final AccountActionListener listener) {
|
||||
itemView.setOnClickListener(v -> listener.onViewAccount(accountId));
|
||||
}
|
||||
|
||||
public void setupLinkListener(final LinkListener listener) {
|
||||
itemView.setOnClickListener(v -> listener.onViewAccount(accountId));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
package com.keylesspalace.tusky.adapter
|
||||
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.keylesspalace.tusky.R
|
||||
import com.keylesspalace.tusky.databinding.ItemAccountBinding
|
||||
import com.keylesspalace.tusky.entity.TimelineAccount
|
||||
import com.keylesspalace.tusky.interfaces.AccountActionListener
|
||||
import com.keylesspalace.tusky.interfaces.LinkListener
|
||||
import com.keylesspalace.tusky.util.emojify
|
||||
import com.keylesspalace.tusky.util.loadAvatar
|
||||
import com.keylesspalace.tusky.util.visible
|
||||
|
||||
class AccountViewHolder(
|
||||
private val binding: ItemAccountBinding
|
||||
) : RecyclerView.ViewHolder(binding.root) {
|
||||
private lateinit var accountId: String
|
||||
|
||||
fun setupWithAccount(
|
||||
account: TimelineAccount,
|
||||
animateAvatar: Boolean,
|
||||
animateEmojis: Boolean,
|
||||
showBotOverlay: Boolean
|
||||
) {
|
||||
accountId = account.id
|
||||
|
||||
binding.accountUsername.text = binding.accountUsername.context.getString(
|
||||
R.string.post_username_format,
|
||||
account.username
|
||||
)
|
||||
|
||||
val emojifiedName = account.name.emojify(
|
||||
account.emojis,
|
||||
binding.accountDisplayName,
|
||||
animateEmojis
|
||||
)
|
||||
binding.accountDisplayName.text = emojifiedName
|
||||
|
||||
val avatarRadius = binding.accountAvatar.context.resources
|
||||
.getDimensionPixelSize(R.dimen.avatar_radius_48dp)
|
||||
loadAvatar(account.avatar, binding.accountAvatar, avatarRadius, animateAvatar)
|
||||
|
||||
binding.accountBotBadge.visible(showBotOverlay && account.bot)
|
||||
}
|
||||
|
||||
fun setupActionListener(listener: AccountActionListener) {
|
||||
itemView.setOnClickListener { listener.onViewAccount(accountId) }
|
||||
}
|
||||
|
||||
fun setupLinkListener(listener: LinkListener) {
|
||||
itemView.setOnClickListener {
|
||||
listener.onViewAccount(
|
||||
accountId
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -31,11 +31,13 @@ import com.keylesspalace.tusky.util.loadAvatar
|
|||
class BlocksAdapter(
|
||||
accountActionListener: AccountActionListener,
|
||||
animateAvatar: Boolean,
|
||||
animateEmojis: Boolean
|
||||
animateEmojis: Boolean,
|
||||
showBotOverlay: Boolean,
|
||||
) : AccountAdapter<BlocksAdapter.BlockedUserViewHolder>(
|
||||
accountActionListener,
|
||||
animateAvatar,
|
||||
animateEmojis
|
||||
animateEmojis,
|
||||
showBotOverlay
|
||||
) {
|
||||
override fun createAccountViewHolder(parent: ViewGroup): BlockedUserViewHolder {
|
||||
val view = LayoutInflater.from(parent.context)
|
||||
|
|
|
@ -16,23 +16,37 @@ package com.keylesspalace.tusky.adapter
|
|||
|
||||
import android.view.LayoutInflater
|
||||
import android.view.ViewGroup
|
||||
import com.keylesspalace.tusky.R
|
||||
import com.keylesspalace.tusky.databinding.ItemAccountBinding
|
||||
import com.keylesspalace.tusky.interfaces.AccountActionListener
|
||||
|
||||
/** Displays either a follows or following list. */
|
||||
class FollowAdapter(
|
||||
accountActionListener: AccountActionListener,
|
||||
animateAvatar: Boolean,
|
||||
animateEmojis: Boolean
|
||||
) : AccountAdapter<AccountViewHolder>(accountActionListener, animateAvatar, animateEmojis) {
|
||||
animateEmojis: Boolean,
|
||||
showBotOverlay: Boolean
|
||||
) : AccountAdapter<AccountViewHolder>(
|
||||
accountActionListener,
|
||||
animateAvatar,
|
||||
animateEmojis,
|
||||
showBotOverlay
|
||||
) {
|
||||
override fun createAccountViewHolder(parent: ViewGroup): AccountViewHolder {
|
||||
val view = LayoutInflater.from(parent.context)
|
||||
.inflate(R.layout.item_account, parent, false)
|
||||
return AccountViewHolder(view)
|
||||
val binding = ItemAccountBinding.inflate(
|
||||
LayoutInflater.from(parent.context),
|
||||
parent,
|
||||
false
|
||||
)
|
||||
return AccountViewHolder(binding)
|
||||
}
|
||||
|
||||
override fun onBindAccountViewHolder(viewHolder: AccountViewHolder, position: Int) {
|
||||
viewHolder.setupWithAccount(accountList[position], animateAvatar, animateEmojis)
|
||||
viewHolder.setupWithAccount(
|
||||
accountList[position],
|
||||
animateAvatar,
|
||||
animateEmojis,
|
||||
showBotOverlay
|
||||
)
|
||||
viewHolder.setupActionListener(accountActionListener)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,7 +34,12 @@ class FollowRequestViewHolder(
|
|||
private val showHeader: Boolean
|
||||
) : RecyclerView.ViewHolder(binding.root) {
|
||||
|
||||
fun setupWithAccount(account: TimelineAccount, animateAvatar: Boolean, animateEmojis: Boolean) {
|
||||
fun setupWithAccount(
|
||||
account: TimelineAccount,
|
||||
animateAvatar: Boolean,
|
||||
animateEmojis: Boolean,
|
||||
showBotOverlay: Boolean
|
||||
) {
|
||||
val wrappedName = account.name.unicodeWrap()
|
||||
val emojifiedName: CharSequence = wrappedName.emojify(account.emojis, itemView, animateEmojis)
|
||||
binding.displayNameTextView.text = emojifiedName
|
||||
|
|
|
@ -23,8 +23,9 @@ import com.keylesspalace.tusky.interfaces.AccountActionListener
|
|||
class FollowRequestsAdapter(
|
||||
accountActionListener: AccountActionListener,
|
||||
animateAvatar: Boolean,
|
||||
animateEmojis: Boolean
|
||||
) : AccountAdapter<FollowRequestViewHolder>(accountActionListener, animateAvatar, animateEmojis) {
|
||||
animateEmojis: Boolean,
|
||||
showBotOverlay: Boolean
|
||||
) : AccountAdapter<FollowRequestViewHolder>(accountActionListener, animateAvatar, animateEmojis, showBotOverlay) {
|
||||
override fun createAccountViewHolder(parent: ViewGroup): FollowRequestViewHolder {
|
||||
val binding = ItemFollowRequestBinding.inflate(
|
||||
LayoutInflater.from(parent.context), parent, false
|
||||
|
@ -33,7 +34,7 @@ class FollowRequestsAdapter(
|
|||
}
|
||||
|
||||
override fun onBindAccountViewHolder(viewHolder: FollowRequestViewHolder, position: Int) {
|
||||
viewHolder.setupWithAccount(accountList[position], animateAvatar, animateEmojis)
|
||||
viewHolder.setupWithAccount(accountList[position], animateAvatar, animateEmojis, showBotOverlay)
|
||||
viewHolder.setupActionListener(accountActionListener, accountList[position].id)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,7 +13,6 @@ import com.keylesspalace.tusky.entity.TimelineAccount
|
|||
import com.keylesspalace.tusky.interfaces.AccountActionListener
|
||||
import com.keylesspalace.tusky.util.emojify
|
||||
import com.keylesspalace.tusky.util.loadAvatar
|
||||
import java.util.HashMap
|
||||
|
||||
/**
|
||||
* Displays a list of muted accounts with mute/unmute account and mute/unmute notifications
|
||||
|
@ -22,11 +21,13 @@ import java.util.HashMap
|
|||
class MutesAdapter(
|
||||
accountActionListener: AccountActionListener,
|
||||
animateAvatar: Boolean,
|
||||
animateEmojis: Boolean
|
||||
animateEmojis: Boolean,
|
||||
showBotOverlay: Boolean
|
||||
) : AccountAdapter<MutesAdapter.MutedUserViewHolder>(
|
||||
accountActionListener,
|
||||
animateAvatar,
|
||||
animateEmojis
|
||||
animateEmojis,
|
||||
showBotOverlay
|
||||
) {
|
||||
private val mutingNotificationsMap = HashMap<String, Boolean>()
|
||||
|
||||
|
|
|
@ -253,7 +253,7 @@ public class NotificationsAdapter extends RecyclerView.Adapter {
|
|||
case VIEW_TYPE_FOLLOW_REQUEST: {
|
||||
if (payloadForHolder == null) {
|
||||
FollowRequestViewHolder holder = (FollowRequestViewHolder) viewHolder;
|
||||
holder.setupWithAccount(concreteNotification.getAccount(), statusDisplayOptions.animateAvatars(), statusDisplayOptions.animateEmojis());
|
||||
holder.setupWithAccount(concreteNotification.getAccount(), statusDisplayOptions.animateAvatars(), statusDisplayOptions.animateEmojis(), statusDisplayOptions.showBotOverlay());
|
||||
holder.setupActionListener(accountActionListener, concreteNotification.getAccount().getId());
|
||||
}
|
||||
break;
|
||||
|
|
|
@ -19,24 +19,27 @@ import android.view.LayoutInflater
|
|||
import android.view.ViewGroup
|
||||
import androidx.paging.PagingDataAdapter
|
||||
import androidx.recyclerview.widget.DiffUtil
|
||||
import com.keylesspalace.tusky.R
|
||||
import com.keylesspalace.tusky.adapter.AccountViewHolder
|
||||
import com.keylesspalace.tusky.databinding.ItemAccountBinding
|
||||
import com.keylesspalace.tusky.entity.TimelineAccount
|
||||
import com.keylesspalace.tusky.interfaces.LinkListener
|
||||
|
||||
class SearchAccountsAdapter(private val linkListener: LinkListener, private val animateAvatars: Boolean, private val animateEmojis: Boolean) :
|
||||
class SearchAccountsAdapter(private val linkListener: LinkListener, private val animateAvatars: Boolean, private val animateEmojis: Boolean, private val showBotOverlay: Boolean) :
|
||||
PagingDataAdapter<TimelineAccount, AccountViewHolder>(ACCOUNT_COMPARATOR) {
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): AccountViewHolder {
|
||||
val view = LayoutInflater.from(parent.context)
|
||||
.inflate(R.layout.item_account, parent, false)
|
||||
return AccountViewHolder(view)
|
||||
val binding = ItemAccountBinding.inflate(
|
||||
LayoutInflater.from(parent.context),
|
||||
parent,
|
||||
false
|
||||
)
|
||||
return AccountViewHolder(binding)
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: AccountViewHolder, position: Int) {
|
||||
getItem(position)?.let { item ->
|
||||
holder.apply {
|
||||
setupWithAccount(item, animateAvatars, animateEmojis)
|
||||
setupWithAccount(item, animateAvatars, animateEmojis, showBotOverlay)
|
||||
setupLinkListener(linkListener)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,7 +30,8 @@ class SearchAccountsFragment : SearchFragment<TimelineAccount>() {
|
|||
return SearchAccountsAdapter(
|
||||
this,
|
||||
preferences.getBoolean(PrefKeys.ANIMATE_GIF_AVATARS, false),
|
||||
preferences.getBoolean(PrefKeys.ANIMATE_CUSTOM_EMOJIS, false)
|
||||
preferences.getBoolean(PrefKeys.ANIMATE_CUSTOM_EMOJIS, false),
|
||||
preferences.getBoolean(PrefKeys.SHOW_BOT_OVERLAY, true)
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -95,17 +95,18 @@ class AccountListFragment : Fragment(R.layout.fragment_account_list), AccountAct
|
|||
val pm = PreferenceManager.getDefaultSharedPreferences(view.context)
|
||||
val animateAvatar = pm.getBoolean(PrefKeys.ANIMATE_GIF_AVATARS, false)
|
||||
val animateEmojis = pm.getBoolean(PrefKeys.ANIMATE_CUSTOM_EMOJIS, false)
|
||||
val showBotOverlay = pm.getBoolean(PrefKeys.SHOW_BOT_OVERLAY, true)
|
||||
|
||||
adapter = when (type) {
|
||||
Type.BLOCKS -> BlocksAdapter(this, animateAvatar, animateEmojis)
|
||||
Type.MUTES -> MutesAdapter(this, animateAvatar, animateEmojis)
|
||||
Type.BLOCKS -> BlocksAdapter(this, animateAvatar, animateEmojis, showBotOverlay)
|
||||
Type.MUTES -> MutesAdapter(this, animateAvatar, animateEmojis, showBotOverlay)
|
||||
Type.FOLLOW_REQUESTS -> {
|
||||
val headerAdapter = FollowRequestsHeaderAdapter(accountManager.activeAccount!!.domain, arguments?.getBoolean(ARG_ACCOUNT_LOCKED) == true)
|
||||
val followRequestsAdapter = FollowRequestsAdapter(this, animateAvatar, animateEmojis)
|
||||
val followRequestsAdapter = FollowRequestsAdapter(this, animateAvatar, animateEmojis, showBotOverlay)
|
||||
binding.recyclerView.adapter = ConcatAdapter(headerAdapter, followRequestsAdapter)
|
||||
followRequestsAdapter
|
||||
}
|
||||
else -> FollowAdapter(this, animateAvatar, animateEmojis)
|
||||
else -> FollowAdapter(this, animateAvatar, animateEmojis, showBotOverlay)
|
||||
}
|
||||
if (binding.recyclerView.adapter == null) {
|
||||
binding.recyclerView.adapter = adapter
|
||||
|
|
|
@ -21,12 +21,13 @@
|
|||
tools:src="@drawable/avatar_default" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/account_avatar_inset"
|
||||
android:id="@+id/account_bot_badge"
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"
|
||||
android:contentDescription="@null"
|
||||
android:importantForAccessibility="no"
|
||||
android:visibility="gone"
|
||||
android:src="@drawable/bot_badge"
|
||||
app:layout_constraintBottom_toBottomOf="@id/account_avatar"
|
||||
app:layout_constraintEnd_toEndOf="@id/account_avatar"
|
||||
tools:src="#000"
|
||||
|
|
Loading…
Reference in a new issue