Improve muted users list (#3127)

* migrate MutesAdapter to viewbinding

* migrate item_muted_user to ConstraintLayout

* add switch instead of button

* change unmute button position

* delete unused string
This commit is contained in:
Konrad Pozniak 2023-01-02 14:09:40 +01:00 committed by GitHub
parent 61a45ae376
commit 33e4da7abb
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 115 additions and 153 deletions

View file

@ -1,16 +1,12 @@
package com.keylesspalace.tusky.adapter package com.keylesspalace.tusky.adapter
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.ImageButton
import android.widget.ImageView
import android.widget.TextView
import androidx.core.view.ViewCompat import androidx.core.view.ViewCompat
import androidx.recyclerview.widget.RecyclerView
import com.keylesspalace.tusky.R import com.keylesspalace.tusky.R
import com.keylesspalace.tusky.entity.TimelineAccount import com.keylesspalace.tusky.databinding.ItemMutedUserBinding
import com.keylesspalace.tusky.interfaces.AccountActionListener import com.keylesspalace.tusky.interfaces.AccountActionListener
import com.keylesspalace.tusky.util.BindingHolder
import com.keylesspalace.tusky.util.emojify import com.keylesspalace.tusky.util.emojify
import com.keylesspalace.tusky.util.loadAvatar import com.keylesspalace.tusky.util.loadAvatar
@ -23,7 +19,7 @@ class MutesAdapter(
animateAvatar: Boolean, animateAvatar: Boolean,
animateEmojis: Boolean, animateEmojis: Boolean,
showBotOverlay: Boolean showBotOverlay: Boolean
) : AccountAdapter<MutesAdapter.MutedUserViewHolder>( ) : AccountAdapter<BindingHolder<ItemMutedUserBinding>>(
accountActionListener, accountActionListener,
animateAvatar, animateAvatar,
animateEmojis, animateEmojis,
@ -31,21 +27,58 @@ class MutesAdapter(
) { ) {
private val mutingNotificationsMap = HashMap<String, Boolean>() private val mutingNotificationsMap = HashMap<String, Boolean>()
override fun createAccountViewHolder(parent: ViewGroup): MutedUserViewHolder { override fun createAccountViewHolder(parent: ViewGroup): BindingHolder<ItemMutedUserBinding> {
val view = LayoutInflater.from(parent.context) val binding = ItemMutedUserBinding.inflate(LayoutInflater.from(parent.context), parent, false)
.inflate(R.layout.item_muted_user, parent, false) return BindingHolder(binding)
return MutedUserViewHolder(view)
} }
override fun onBindAccountViewHolder(viewHolder: MutedUserViewHolder, position: Int) { override fun onBindAccountViewHolder(viewHolder: BindingHolder<ItemMutedUserBinding>, position: Int) {
val account = accountList[position] val account = accountList[position]
viewHolder.setupWithAccount( val binding = viewHolder.binding
account, val context = binding.root.context
mutingNotificationsMap[account.id],
animateAvatar, val mutingNotifications = mutingNotificationsMap[account.id]
animateEmojis
) val emojifiedName = account.name.emojify(account.emojis, binding.mutedUserDisplayName, animateEmojis)
viewHolder.setupActionListener(accountActionListener) binding.mutedUserDisplayName.text = emojifiedName
val formattedUsername = context.getString(R.string.post_username_format, account.username)
binding.mutedUserUsername.text = formattedUsername
val avatarRadius = context.resources.getDimensionPixelSize(R.dimen.avatar_radius_48dp)
loadAvatar(account.avatar, binding.mutedUserAvatar, avatarRadius, animateAvatar)
val unmuteString = context.getString(R.string.action_unmute_desc, formattedUsername)
binding.mutedUserUnmute.contentDescription = unmuteString
ViewCompat.setTooltipText(binding.mutedUserUnmute, unmuteString)
binding.mutedUserMuteNotifications.setOnCheckedChangeListener(null)
binding.mutedUserMuteNotifications.isChecked = if (mutingNotifications == null) {
binding.mutedUserMuteNotifications.isEnabled = false
true
} else {
binding.mutedUserMuteNotifications.isEnabled = true
mutingNotifications
}
binding.mutedUserUnmute.setOnClickListener {
accountActionListener.onMute(
false,
account.id,
viewHolder.bindingAdapterPosition,
false
)
}
binding.mutedUserMuteNotifications.setOnCheckedChangeListener { _, isChecked ->
accountActionListener.onMute(
true,
account.id,
viewHolder.bindingAdapterPosition,
isChecked
)
}
binding.root.setOnClickListener { accountActionListener.onViewAccount(account.id) }
} }
fun updateMutingNotifications(id: String, mutingNotifications: Boolean, position: Int) { fun updateMutingNotifications(id: String, mutingNotifications: Boolean, position: Int) {
@ -53,81 +86,8 @@ class MutesAdapter(
notifyItemChanged(position) notifyItemChanged(position)
} }
fun updateMutingNotificationsMap(newMutingNotificationsMap: HashMap<String, Boolean>?) { fun updateMutingNotificationsMap(newMutingNotificationsMap: HashMap<String, Boolean>) {
mutingNotificationsMap.putAll(newMutingNotificationsMap!!) mutingNotificationsMap.putAll(newMutingNotificationsMap)
notifyDataSetChanged() notifyDataSetChanged()
} }
class MutedUserViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
private val avatar: ImageView = itemView.findViewById(R.id.muted_user_avatar)
private val username: TextView = itemView.findViewById(R.id.muted_user_username)
private val displayName: TextView = itemView.findViewById(R.id.muted_user_display_name)
private val unmute: ImageButton = itemView.findViewById(R.id.muted_user_unmute)
private val muteNotifications: ImageButton =
itemView.findViewById(R.id.muted_user_mute_notifications)
private var id: String? = null
private var notifications = false
fun setupWithAccount(
account: TimelineAccount,
mutingNotifications: Boolean?,
animateAvatar: Boolean,
animateEmojis: Boolean
) {
id = account.id
val emojifiedName = account.name.emojify(account.emojis, displayName, animateEmojis)
displayName.text = emojifiedName
val format = username.context.getString(R.string.post_username_format)
val formattedUsername = String.format(format, account.username)
username.text = formattedUsername
val avatarRadius = avatar.context.resources
.getDimensionPixelSize(R.dimen.avatar_radius_48dp)
loadAvatar(account.avatar, avatar, avatarRadius, animateAvatar)
val unmuteString =
unmute.context.getString(R.string.action_unmute_desc, formattedUsername)
unmute.contentDescription = unmuteString
ViewCompat.setTooltipText(unmute, unmuteString)
if (mutingNotifications == null) {
muteNotifications.isEnabled = false
notifications = true
} else {
muteNotifications.isEnabled = true
notifications = mutingNotifications
}
if (notifications) {
muteNotifications.setImageResource(R.drawable.ic_notifications_24dp)
val unmuteNotificationsString = muteNotifications.context
.getString(R.string.action_unmute_notifications_desc, formattedUsername)
muteNotifications.contentDescription = unmuteNotificationsString
ViewCompat.setTooltipText(muteNotifications, unmuteNotificationsString)
} else {
muteNotifications.setImageResource(R.drawable.ic_notifications_off_24dp)
val muteNotificationsString = muteNotifications.context
.getString(R.string.action_mute_notifications_desc, formattedUsername)
muteNotifications.contentDescription = muteNotificationsString
ViewCompat.setTooltipText(muteNotifications, muteNotificationsString)
}
}
fun setupActionListener(listener: AccountActionListener) {
unmute.setOnClickListener {
listener.onMute(
false,
id,
bindingAdapterPosition,
false
)
}
muteNotifications.setOnClickListener {
listener.onMute(
true,
id,
bindingAdapterPosition,
!notifications
)
}
itemView.setOnClickListener { listener.onViewAccount(id) }
}
}
} }

View file

@ -394,7 +394,7 @@ class AccountListFragment : Fragment(R.layout.fragment_account_list), AccountAct
fun newInstance(type: Type, id: String? = null, accountLocked: Boolean = false): AccountListFragment { fun newInstance(type: Type, id: String? = null, accountLocked: Boolean = false): AccountListFragment {
return AccountListFragment().apply { return AccountListFragment().apply {
arguments = Bundle(2).apply { arguments = Bundle(3).apply {
putSerializable(ARG_TYPE, type) putSerializable(ARG_TYPE, type)
putString(ARG_ID, id) putString(ARG_ID, id)
putBoolean(ARG_ACCOUNT_LOCKED, accountLocked) putBoolean(ARG_ACCOUNT_LOCKED, accountLocked)

View file

@ -1,77 +1,80 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="72dp" android:layout_height="wrap_content"
android:gravity="center_vertical" android:paddingStart="16dp"
android:paddingLeft="16dp" android:paddingEnd="16dp">
android:paddingRight="16dp">
<ImageView <ImageView
android:id="@+id/muted_user_avatar" android:id="@+id/muted_user_avatar"
android:layout_width="48dp" android:layout_width="48dp"
android:layout_height="48dp" android:layout_height="48dp"
android:layout_alignParentStart="true"
android:layout_centerVertical="true" android:layout_centerVertical="true"
android:layout_marginEnd="24dp" android:layout_marginTop="10dp"
android:contentDescription="@string/action_view_profile" /> android:layout_marginBottom="10dp"
android:contentDescription="@string/action_view_profile"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:src="@drawable/avatar_default" />
<TextView
android:id="@+id/muted_user_display_name"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="24dp"
android:ellipsize="end"
android:maxLines="1"
android:textColor="?android:textColorPrimary"
android:textSize="?attr/status_text_large"
android:textStyle="normal|bold"
app:layout_constrainedWidth="true"
app:layout_constraintBottom_toTopOf="@id/muted_user_username"
app:layout_constraintEnd_toStartOf="@id/muted_user_unmute"
app:layout_constraintStart_toEndOf="@id/muted_user_avatar"
app:layout_constraintTop_toTopOf="@id/muted_user_avatar"
tools:text="Display name" />
<TextView
android:id="@+id/muted_user_username"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:ellipsize="end"
android:maxLines="1"
android:textColor="?android:textColorSecondary"
android:textSize="?attr/status_text_medium"
app:layout_constraintBottom_toBottomOf="@id/muted_user_avatar"
app:layout_constraintEnd_toEndOf="@id/muted_user_display_name"
app:layout_constraintStart_toStartOf="@id/muted_user_display_name"
app:layout_constraintTop_toBottomOf="@id/muted_user_display_name"
tools:text="\@username" />
<ImageButton <ImageButton
android:id="@+id/muted_user_unmute" android:id="@+id/muted_user_unmute"
style="@style/TuskyImageButton" style="@style/TuskyImageButton"
android:layout_width="32dp" android:layout_width="48dp"
android:layout_height="32dp" android:layout_height="48dp"
android:layout_toStartOf="@id/muted_user_mute_notifications"
android:layout_centerVertical="true"
android:layout_gravity="center_vertical"
android:layout_marginStart="12dp" android:layout_marginStart="12dp"
android:background="?attr/selectableItemBackgroundBorderless" android:background="?attr/selectableItemBackgroundBorderless"
android:padding="4dp" android:padding="4dp"
app:srcCompat="@drawable/ic_unmute_24dp" /> app:layout_constraintBottom_toBottomOf="@id/muted_user_avatar"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/ic_clear_24dp"
tools:ignore="ContentDescription" />
<ImageButton <com.google.android.material.switchmaterial.SwitchMaterial
android:text="@string/mute_notifications_switch"
android:id="@+id/muted_user_mute_notifications" android:id="@+id/muted_user_mute_notifications"
style="@style/TuskyImageButton"
android:layout_width="32dp"
android:layout_height="32dp"
android:layout_alignParentEnd="true"
android:layout_centerVertical="true"
android:layout_gravity="center_vertical"
android:layout_marginStart="12dp"
android:background="?attr/selectableItemBackgroundBorderless"
android:padding="4dp"
app:srcCompat="@drawable/ic_notifications_24dp" />
<LinearLayout
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="match_parent" android:layout_height="wrap_content"
android:layout_toEndOf="@id/muted_user_avatar" android:layout_marginBottom="4dp"
android:layout_toStartOf="@id/muted_user_unmute" android:textColor="?android:textColorTertiary"
android:gravity="center_vertical" android:layout_marginTop="4dp"
android:orientation="vertical"> app:layout_constraintBottom_toBottomOf="parent"
app:switchPadding="4dp"
app:layout_constraintStart_toStartOf="@id/muted_user_display_name"
app:layout_constraintTop_toBottomOf="@id/muted_user_username" />
<TextView </androidx.constraintlayout.widget.ConstraintLayout>
android:id="@+id/muted_user_display_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="end"
android:maxLines="1"
android:textColor="?android:textColorPrimary"
android:textSize="?attr/status_text_large"
android:textStyle="normal|bold"
tools:text="Display name" />
<TextView
android:id="@+id/muted_user_username"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="end"
android:maxLines="1"
android:textColor="?android:textColorSecondary"
android:textSize="?attr/status_text_medium"
tools:text="\@username" />
</LinearLayout>
</RelativeLayout>

View file

@ -134,8 +134,6 @@
<string name="action_mute">Mute</string> <string name="action_mute">Mute</string>
<string name="action_unmute">Unmute</string> <string name="action_unmute">Unmute</string>
<string name="action_unmute_desc">Unmute %s</string> <string name="action_unmute_desc">Unmute %s</string>
<string name="action_unmute_notifications_desc">Unmute notifications from %s</string>
<string name="action_mute_notifications_desc">Mute notifications from %s</string>
<string name="action_mute_domain">Mute %s</string> <string name="action_mute_domain">Mute %s</string>
<string name="action_unmute_domain">Unmute %s</string> <string name="action_unmute_domain">Unmute %s</string>
<string name="action_mute_conversation">Mute conversation</string> <string name="action_mute_conversation">Mute conversation</string>
@ -712,6 +710,7 @@
<string name="report_category_other">Other</string> <string name="report_category_other">Other</string>
<string name="action_unfollow_hashtag_format">Unfollow #%s?</string> <string name="action_unfollow_hashtag_format">Unfollow #%s?</string>
<string name="mute_notifications_switch">Mute notifications</string>
<!--@Tusky edited 19th December 2022 13:37 --> <!--@Tusky edited 19th December 2022 13:37 -->
<string name="status_edit_info">%1$s edited %2$s</string> <string name="status_edit_info">%1$s edited %2$s</string>