Clean up Account adapters (#3202)

* make BlocksAdapter use viewbinding

* remove LoadingFooterViewHolder

* cleanup code

* move accountlist to component packes

* make FollowRequestsHeaderAdapter use viewbinding

* add license to MutesAdapter

* move accountlist to component packages

* use ConstraintLayout in item_blocked_user.xml

* support the bot badge everywhere

* cleanup code

* cleanup xml files

* ktlint

* ktlint
This commit is contained in:
Konrad Pozniak 2023-02-04 20:29:13 +01:00 committed by GitHub
parent 006f0de05c
commit 15ff6191ae
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
25 changed files with 254 additions and 229 deletions

View File

@ -122,7 +122,7 @@
<activity android:name=".EditProfileActivity" /> <activity android:name=".EditProfileActivity" />
<activity android:name=".components.preference.PreferencesActivity" /> <activity android:name=".components.preference.PreferencesActivity" />
<activity android:name=".StatusListActivity" /> <activity android:name=".StatusListActivity" />
<activity android:name=".AccountListActivity" /> <activity android:name=".components.accountlist.AccountListActivity" />
<activity android:name=".AboutActivity" /> <activity android:name=".AboutActivity" />
<activity android:name=".TabPreferenceActivity" /> <activity android:name=".TabPreferenceActivity" />
<activity <activity

View File

@ -62,6 +62,7 @@ import com.keylesspalace.tusky.appstore.EventHub
import com.keylesspalace.tusky.appstore.MainTabsChangedEvent import com.keylesspalace.tusky.appstore.MainTabsChangedEvent
import com.keylesspalace.tusky.appstore.ProfileEditedEvent import com.keylesspalace.tusky.appstore.ProfileEditedEvent
import com.keylesspalace.tusky.components.account.AccountActivity import com.keylesspalace.tusky.components.account.AccountActivity
import com.keylesspalace.tusky.components.accountlist.AccountListActivity
import com.keylesspalace.tusky.components.announcements.AnnouncementsActivity import com.keylesspalace.tusky.components.announcements.AnnouncementsActivity
import com.keylesspalace.tusky.components.compose.ComposeActivity import com.keylesspalace.tusky.components.compose.ComposeActivity
import com.keylesspalace.tusky.components.compose.ComposeActivity.Companion.canHandleMimeType import com.keylesspalace.tusky.components.compose.ComposeActivity.Companion.canHandleMimeType

View File

@ -1,82 +0,0 @@
/* Copyright 2017 Andrew Dawson
*
* This file is a part of Tusky.
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
* License, or (at your option) any later version.
*
* Tusky is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License along with Tusky; if not,
* see <http://www.gnu.org/licenses>. */
package com.keylesspalace.tusky.adapter
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageButton
import android.widget.ImageView
import android.widget.TextView
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.util.emojify
import com.keylesspalace.tusky.util.loadAvatar
/** Displays a list of blocked accounts. */
class BlocksAdapter(
accountActionListener: AccountActionListener,
animateAvatar: Boolean,
animateEmojis: Boolean,
showBotOverlay: Boolean,
) : AccountAdapter<BlocksAdapter.BlockedUserViewHolder>(
accountActionListener,
animateAvatar,
animateEmojis,
showBotOverlay
) {
override fun createAccountViewHolder(parent: ViewGroup): BlockedUserViewHolder {
val view = LayoutInflater.from(parent.context)
.inflate(R.layout.item_blocked_user, parent, false)
return BlockedUserViewHolder(view)
}
override fun onBindAccountViewHolder(viewHolder: BlockedUserViewHolder, position: Int) {
viewHolder.setupWithAccount(accountList[position], animateAvatar, animateEmojis)
viewHolder.setupActionListener(accountActionListener)
}
class BlockedUserViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
private val avatar: ImageView = itemView.findViewById(R.id.blocked_user_avatar)
private val username: TextView = itemView.findViewById(R.id.blocked_user_username)
private val displayName: TextView = itemView.findViewById(R.id.blocked_user_display_name)
private val unblock: ImageButton = itemView.findViewById(R.id.blocked_user_unblock)
private var id: String? = null
fun setupWithAccount(account: TimelineAccount, 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)
}
fun setupActionListener(listener: AccountActionListener) {
unblock.setOnClickListener {
val position = bindingAdapterPosition
if (position != RecyclerView.NO_POSITION) {
listener.onBlock(false, id, position)
}
}
itemView.setOnClickListener { listener.onViewAccount(id) }
}
}
}

View File

@ -50,11 +50,11 @@ class FollowRequestViewHolder(
}.emojify(account.emojis, itemView, animateEmojis) }.emojify(account.emojis, itemView, animateEmojis)
} }
binding.notificationTextView.visible(showHeader) binding.notificationTextView.visible(showHeader)
val format = itemView.context.getString(R.string.post_username_format) val formattedUsername = itemView.context.getString(R.string.post_username_format, account.username)
val formattedUsername = String.format(format, account.username)
binding.usernameTextView.text = formattedUsername binding.usernameTextView.text = formattedUsername
val avatarRadius = binding.avatar.context.resources.getDimensionPixelSize(R.dimen.avatar_radius_48dp) val avatarRadius = binding.avatar.context.resources.getDimensionPixelSize(R.dimen.avatar_radius_48dp)
loadAvatar(account.avatar, binding.avatar, avatarRadius, animateAvatar) loadAvatar(account.avatar, binding.avatar, avatarRadius, animateAvatar)
binding.avatarBadge.visible(showBotOverlay && account.bot)
} }
fun setupActionListener(listener: AccountActionListener, accountId: String) { fun setupActionListener(listener: AccountActionListener, accountId: String) {

View File

@ -1,21 +0,0 @@
/* Copyright 2018 Conny Duck
*
* This file is a part of Tusky.
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
* License, or (at your option) any later version.
*
* Tusky is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License along with Tusky; if not,
* see <http://www.gnu.org/licenses>. */
package com.keylesspalace.tusky.adapter
import android.view.View
import androidx.recyclerview.widget.RecyclerView
class LoadingFooterViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView)

View File

@ -50,13 +50,13 @@ import com.google.android.material.shape.ShapeAppearanceModel
import com.google.android.material.snackbar.Snackbar import com.google.android.material.snackbar.Snackbar
import com.google.android.material.tabs.TabLayout import com.google.android.material.tabs.TabLayout
import com.google.android.material.tabs.TabLayoutMediator import com.google.android.material.tabs.TabLayoutMediator
import com.keylesspalace.tusky.AccountListActivity
import com.keylesspalace.tusky.BottomSheetActivity import com.keylesspalace.tusky.BottomSheetActivity
import com.keylesspalace.tusky.EditProfileActivity import com.keylesspalace.tusky.EditProfileActivity
import com.keylesspalace.tusky.R import com.keylesspalace.tusky.R
import com.keylesspalace.tusky.StatusListActivity import com.keylesspalace.tusky.StatusListActivity
import com.keylesspalace.tusky.ViewMediaActivity import com.keylesspalace.tusky.ViewMediaActivity
import com.keylesspalace.tusky.components.account.list.ListsForAccountFragment import com.keylesspalace.tusky.components.account.list.ListsForAccountFragment
import com.keylesspalace.tusky.components.accountlist.AccountListActivity
import com.keylesspalace.tusky.components.compose.ComposeActivity import com.keylesspalace.tusky.components.compose.ComposeActivity
import com.keylesspalace.tusky.components.report.ReportActivity import com.keylesspalace.tusky.components.report.ReportActivity
import com.keylesspalace.tusky.databinding.ActivityAccountBinding import com.keylesspalace.tusky.databinding.ActivityAccountBinding

View File

@ -13,13 +13,15 @@
* You should have received a copy of the GNU General Public License along with Tusky; if not, * You should have received a copy of the GNU General Public License along with Tusky; if not,
* see <http://www.gnu.org/licenses>. */ * see <http://www.gnu.org/licenses>. */
package com.keylesspalace.tusky package com.keylesspalace.tusky.components.accountlist
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.os.Bundle import android.os.Bundle
import androidx.fragment.app.commit
import com.keylesspalace.tusky.BaseActivity
import com.keylesspalace.tusky.R
import com.keylesspalace.tusky.databinding.ActivityAccountListBinding import com.keylesspalace.tusky.databinding.ActivityAccountListBinding
import com.keylesspalace.tusky.fragment.AccountListFragment
import dagger.android.DispatchingAndroidInjector import dagger.android.DispatchingAndroidInjector
import dagger.android.HasAndroidInjector import dagger.android.HasAndroidInjector
import javax.inject.Inject import javax.inject.Inject
@ -63,10 +65,9 @@ class AccountListActivity : BaseActivity(), HasAndroidInjector {
setDisplayShowHomeEnabled(true) setDisplayShowHomeEnabled(true)
} }
supportFragmentManager supportFragmentManager.commit {
.beginTransaction() replace(R.id.fragment_container, AccountListFragment.newInstance(type, id, accountLocked))
.replace(R.id.fragment_container, AccountListFragment.newInstance(type, id, accountLocked)) }
.commit()
} }
override fun androidInjector() = dispatchingAndroidInjector override fun androidInjector() = dispatchingAndroidInjector
@ -76,8 +77,6 @@ class AccountListActivity : BaseActivity(), HasAndroidInjector {
private const val EXTRA_ID = "id" private const val EXTRA_ID = "id"
private const val EXTRA_ACCOUNT_LOCKED = "acc_locked" private const val EXTRA_ACCOUNT_LOCKED = "acc_locked"
@JvmStatic
@JvmOverloads
fun newIntent(context: Context, type: Type, id: String? = null, accountLocked: Boolean = false): Intent { fun newIntent(context: Context, type: Type, id: String? = null, accountLocked: Boolean = false): Intent {
return Intent(context, AccountListActivity::class.java).apply { return Intent(context, AccountListActivity::class.java).apply {
putExtra(EXTRA_TYPE, type) putExtra(EXTRA_TYPE, type)

View File

@ -13,7 +13,7 @@
* You should have received a copy of the GNU General Public License along with Tusky; if not, * You should have received a copy of the GNU General Public License along with Tusky; if not,
* see <http://www.gnu.org/licenses>. */ * see <http://www.gnu.org/licenses>. */
package com.keylesspalace.tusky.fragment package com.keylesspalace.tusky.components.accountlist
import android.os.Bundle import android.os.Bundle
import android.util.Log import android.util.Log
@ -30,16 +30,16 @@ import androidx.recyclerview.widget.SimpleItemAnimator
import autodispose2.androidx.lifecycle.AndroidLifecycleScopeProvider.from import autodispose2.androidx.lifecycle.AndroidLifecycleScopeProvider.from
import autodispose2.autoDispose import autodispose2.autoDispose
import com.google.android.material.snackbar.Snackbar import com.google.android.material.snackbar.Snackbar
import com.keylesspalace.tusky.AccountListActivity.Type
import com.keylesspalace.tusky.BaseActivity import com.keylesspalace.tusky.BaseActivity
import com.keylesspalace.tusky.R import com.keylesspalace.tusky.R
import com.keylesspalace.tusky.adapter.AccountAdapter
import com.keylesspalace.tusky.adapter.BlocksAdapter
import com.keylesspalace.tusky.adapter.FollowAdapter
import com.keylesspalace.tusky.adapter.FollowRequestsAdapter
import com.keylesspalace.tusky.adapter.FollowRequestsHeaderAdapter
import com.keylesspalace.tusky.adapter.MutesAdapter
import com.keylesspalace.tusky.components.account.AccountActivity import com.keylesspalace.tusky.components.account.AccountActivity
import com.keylesspalace.tusky.components.accountlist.AccountListActivity.Type
import com.keylesspalace.tusky.components.accountlist.adapter.AccountAdapter
import com.keylesspalace.tusky.components.accountlist.adapter.BlocksAdapter
import com.keylesspalace.tusky.components.accountlist.adapter.FollowAdapter
import com.keylesspalace.tusky.components.accountlist.adapter.FollowRequestsAdapter
import com.keylesspalace.tusky.components.accountlist.adapter.FollowRequestsHeaderAdapter
import com.keylesspalace.tusky.components.accountlist.adapter.MutesAdapter
import com.keylesspalace.tusky.databinding.FragmentAccountListBinding import com.keylesspalace.tusky.databinding.FragmentAccountListBinding
import com.keylesspalace.tusky.db.AccountManager import com.keylesspalace.tusky.db.AccountManager
import com.keylesspalace.tusky.di.Injectable import com.keylesspalace.tusky.di.Injectable
@ -83,7 +83,6 @@ class AccountListFragment : Fragment(R.layout.fragment_account_list), AccountAct
} }
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding.recyclerView.setHasFixedSize(true) binding.recyclerView.setHasFixedSize(true)
val layoutManager = LinearLayoutManager(view.context) val layoutManager = LinearLayoutManager(view.context)
@ -101,7 +100,10 @@ class AccountListFragment : Fragment(R.layout.fragment_account_list), AccountAct
Type.BLOCKS -> BlocksAdapter(this, animateAvatar, animateEmojis, showBotOverlay) Type.BLOCKS -> BlocksAdapter(this, animateAvatar, animateEmojis, showBotOverlay)
Type.MUTES -> MutesAdapter(this, animateAvatar, animateEmojis, showBotOverlay) Type.MUTES -> MutesAdapter(this, animateAvatar, animateEmojis, showBotOverlay)
Type.FOLLOW_REQUESTS -> { Type.FOLLOW_REQUESTS -> {
val headerAdapter = FollowRequestsHeaderAdapter(accountManager.activeAccount!!.domain, arguments?.getBoolean(ARG_ACCOUNT_LOCKED) == true) val headerAdapter = FollowRequestsHeaderAdapter(
instanceName = accountManager.activeAccount!!.domain,
accountLocked = arguments?.getBoolean(ARG_ACCOUNT_LOCKED) == true
)
val followRequestsAdapter = FollowRequestsAdapter(this, animateAvatar, animateEmojis, showBotOverlay) val followRequestsAdapter = FollowRequestsAdapter(this, animateAvatar, animateEmojis, showBotOverlay)
binding.recyclerView.adapter = ConcatAdapter(headerAdapter, followRequestsAdapter) binding.recyclerView.adapter = ConcatAdapter(headerAdapter, followRequestsAdapter)
followRequestsAdapter followRequestsAdapter
@ -350,8 +352,8 @@ class AccountListFragment : Fragment(R.layout.fragment_account_list), AccountAct
api.relationships(ids) api.relationships(ids)
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
.autoDispose(from(this)) .autoDispose(from(this))
.subscribe(::onFetchRelationshipsSuccess) { .subscribe(::onFetchRelationshipsSuccess) { throwable ->
onFetchRelationshipsFailure(ids) Log.e(TAG, "Fetch failure for relationships of accounts: $ids", throwable)
} }
} }
@ -362,10 +364,6 @@ class AccountListFragment : Fragment(R.layout.fragment_account_list), AccountAct
mutesAdapter.updateMutingNotificationsMap(mutingNotificationsMap) mutesAdapter.updateMutingNotificationsMap(mutingNotificationsMap)
} }
private fun onFetchRelationshipsFailure(ids: List<String>) {
Log.e(TAG, "Fetch failure for relationships of accounts: $ids")
}
private fun onFetchAccountsFailure(throwable: Throwable) { private fun onFetchAccountsFailure(throwable: Throwable) {
fetching = false fetching = false
Log.e(TAG, "Fetch failure", throwable) Log.e(TAG, "Fetch failure", throwable)

View File

@ -12,24 +12,26 @@
* *
* You should have received a copy of the GNU General Public License along with Tusky; if not, * You should have received a copy of the GNU General Public License along with Tusky; if not,
* see <http://www.gnu.org/licenses>. */ * see <http://www.gnu.org/licenses>. */
package com.keylesspalace.tusky.adapter package com.keylesspalace.tusky.components.accountlist.adapter
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.ViewGroup import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import com.keylesspalace.tusky.R import com.keylesspalace.tusky.databinding.ItemFooterBinding
import com.keylesspalace.tusky.entity.TimelineAccount import com.keylesspalace.tusky.entity.TimelineAccount
import com.keylesspalace.tusky.interfaces.AccountActionListener import com.keylesspalace.tusky.interfaces.AccountActionListener
import com.keylesspalace.tusky.util.BindingHolder
import com.keylesspalace.tusky.util.removeDuplicates import com.keylesspalace.tusky.util.removeDuplicates
/** Generic adapter with bottom loading indicator. */ /** Generic adapter with bottom loading indicator. */
abstract class AccountAdapter<AVH : RecyclerView.ViewHolder> internal constructor( abstract class AccountAdapter<AVH : RecyclerView.ViewHolder> internal constructor(
var accountActionListener: AccountActionListener, protected val accountActionListener: AccountActionListener,
protected val animateAvatar: Boolean, protected val animateAvatar: Boolean,
protected val animateEmojis: Boolean, protected val animateEmojis: Boolean,
protected val showBotOverlay: Boolean protected val showBotOverlay: Boolean
) : RecyclerView.Adapter<RecyclerView.ViewHolder?>() { ) : RecyclerView.Adapter<RecyclerView.ViewHolder?>() {
var accountList = mutableListOf<TimelineAccount>()
protected var accountList: MutableList<TimelineAccount> = mutableListOf()
private var bottomLoading: Boolean = false private var bottomLoading: Boolean = false
override fun getItemCount(): Int { override fun getItemCount(): Int {
@ -61,9 +63,8 @@ abstract class AccountAdapter<AVH : RecyclerView.ViewHolder> internal constructo
private fun createFooterViewHolder( private fun createFooterViewHolder(
parent: ViewGroup, parent: ViewGroup,
): RecyclerView.ViewHolder { ): RecyclerView.ViewHolder {
val view = LayoutInflater.from(parent.context) val binding = ItemFooterBinding.inflate(LayoutInflater.from(parent.context), parent, false)
.inflate(R.layout.item_footer, parent, false) return BindingHolder(binding)
return LoadingFooterViewHolder(view)
} }
override fun getItemViewType(position: Int): Int { override fun getItemViewType(position: Int): Int {

View File

@ -0,0 +1,68 @@
/* Copyright 2017 Andrew Dawson
*
* This file is a part of Tusky.
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
* License, or (at your option) any later version.
*
* Tusky is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License along with Tusky; if not,
* see <http://www.gnu.org/licenses>. */
package com.keylesspalace.tusky.components.accountlist.adapter
import android.view.LayoutInflater
import android.view.ViewGroup
import com.keylesspalace.tusky.R
import com.keylesspalace.tusky.databinding.ItemBlockedUserBinding
import com.keylesspalace.tusky.interfaces.AccountActionListener
import com.keylesspalace.tusky.util.BindingHolder
import com.keylesspalace.tusky.util.emojify
import com.keylesspalace.tusky.util.loadAvatar
import com.keylesspalace.tusky.util.visible
/** Displays a list of blocked accounts. */
class BlocksAdapter(
accountActionListener: AccountActionListener,
animateAvatar: Boolean,
animateEmojis: Boolean,
showBotOverlay: Boolean,
) : AccountAdapter<BindingHolder<ItemBlockedUserBinding>>(
accountActionListener = accountActionListener,
animateAvatar = animateAvatar,
animateEmojis = animateEmojis,
showBotOverlay = showBotOverlay
) {
override fun createAccountViewHolder(parent: ViewGroup): BindingHolder<ItemBlockedUserBinding> {
val binding = ItemBlockedUserBinding.inflate(LayoutInflater.from(parent.context), parent, false)
return BindingHolder(binding)
}
override fun onBindAccountViewHolder(viewHolder: BindingHolder<ItemBlockedUserBinding>, position: Int) {
val account = accountList[position]
val binding = viewHolder.binding
val context = binding.root.context
val emojifiedName = account.name.emojify(account.emojis, binding.blockedUserDisplayName, animateEmojis)
binding.blockedUserDisplayName.text = emojifiedName
val formattedUsername = context.getString(R.string.post_username_format, account.username)
binding.blockedUserUsername.text = formattedUsername
val avatarRadius = context.resources.getDimensionPixelSize(R.dimen.avatar_radius_48dp)
loadAvatar(account.avatar, binding.blockedUserAvatar, avatarRadius, animateAvatar)
binding.blockedUserBotBadge.visible(showBotOverlay && account.bot)
binding.blockedUserUnblock.setOnClickListener {
accountActionListener.onBlock(false, account.id, position)
}
binding.root.setOnClickListener {
accountActionListener.onViewAccount(account.id)
}
}
}

View File

@ -12,10 +12,12 @@
* *
* You should have received a copy of the GNU General Public License along with Tusky; if not, * You should have received a copy of the GNU General Public License along with Tusky; if not,
* see <http://www.gnu.org/licenses>. */ * see <http://www.gnu.org/licenses>. */
package com.keylesspalace.tusky.adapter
package com.keylesspalace.tusky.components.accountlist.adapter
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.ViewGroup import android.view.ViewGroup
import com.keylesspalace.tusky.adapter.AccountViewHolder
import com.keylesspalace.tusky.databinding.ItemAccountBinding import com.keylesspalace.tusky.databinding.ItemAccountBinding
import com.keylesspalace.tusky.interfaces.AccountActionListener import com.keylesspalace.tusky.interfaces.AccountActionListener
@ -26,17 +28,14 @@ class FollowAdapter(
animateEmojis: Boolean, animateEmojis: Boolean,
showBotOverlay: Boolean showBotOverlay: Boolean
) : AccountAdapter<AccountViewHolder>( ) : AccountAdapter<AccountViewHolder>(
accountActionListener, accountActionListener = accountActionListener,
animateAvatar, animateAvatar = animateAvatar,
animateEmojis, animateEmojis = animateEmojis,
showBotOverlay showBotOverlay = showBotOverlay
) { ) {
override fun createAccountViewHolder(parent: ViewGroup): AccountViewHolder { override fun createAccountViewHolder(parent: ViewGroup): AccountViewHolder {
val binding = ItemAccountBinding.inflate( val binding = ItemAccountBinding.inflate(LayoutInflater.from(parent.context), parent, false)
LayoutInflater.from(parent.context),
parent,
false
)
return AccountViewHolder(binding) return AccountViewHolder(binding)
} }

View File

@ -12,10 +12,12 @@
* *
* You should have received a copy of the GNU General Public License along with Tusky; if not, * You should have received a copy of the GNU General Public License along with Tusky; if not,
* see <http://www.gnu.org/licenses>. */ * see <http://www.gnu.org/licenses>. */
package com.keylesspalace.tusky.adapter
package com.keylesspalace.tusky.components.accountlist.adapter
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.ViewGroup import android.view.ViewGroup
import com.keylesspalace.tusky.adapter.FollowRequestViewHolder
import com.keylesspalace.tusky.databinding.ItemFollowRequestBinding import com.keylesspalace.tusky.databinding.ItemFollowRequestBinding
import com.keylesspalace.tusky.interfaces.AccountActionListener import com.keylesspalace.tusky.interfaces.AccountActionListener
@ -25,16 +27,25 @@ class FollowRequestsAdapter(
animateAvatar: Boolean, animateAvatar: Boolean,
animateEmojis: Boolean, animateEmojis: Boolean,
showBotOverlay: Boolean showBotOverlay: Boolean
) : AccountAdapter<FollowRequestViewHolder>(accountActionListener, animateAvatar, animateEmojis, showBotOverlay) { ) : AccountAdapter<FollowRequestViewHolder>(
accountActionListener = accountActionListener,
animateAvatar = animateAvatar,
animateEmojis = animateEmojis,
showBotOverlay = showBotOverlay
) {
override fun createAccountViewHolder(parent: ViewGroup): FollowRequestViewHolder { override fun createAccountViewHolder(parent: ViewGroup): FollowRequestViewHolder {
val binding = ItemFollowRequestBinding.inflate( val binding = ItemFollowRequestBinding.inflate(LayoutInflater.from(parent.context), parent, false)
LayoutInflater.from(parent.context), parent, false
)
return FollowRequestViewHolder(binding, false) return FollowRequestViewHolder(binding, false)
} }
override fun onBindAccountViewHolder(viewHolder: FollowRequestViewHolder, position: Int) { override fun onBindAccountViewHolder(viewHolder: FollowRequestViewHolder, position: Int) {
viewHolder.setupWithAccount(accountList[position], animateAvatar, animateEmojis, showBotOverlay) viewHolder.setupWithAccount(
account = accountList[position],
animateAvatar = animateAvatar,
animateEmojis = animateEmojis,
showBotOverlay = showBotOverlay
)
viewHolder.setupActionListener(accountActionListener, accountList[position].id) viewHolder.setupActionListener(accountActionListener, accountList[position].id)
} }
} }

View File

@ -13,27 +13,28 @@
* You should have received a copy of the GNU General Public License along with Tusky; if not, * You should have received a copy of the GNU General Public License along with Tusky; if not,
* see <http://www.gnu.org/licenses>. */ * see <http://www.gnu.org/licenses>. */
package com.keylesspalace.tusky.adapter package com.keylesspalace.tusky.components.accountlist.adapter
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import com.keylesspalace.tusky.R import com.keylesspalace.tusky.R
import com.keylesspalace.tusky.databinding.ItemFollowRequestsHeaderBinding
import com.keylesspalace.tusky.util.BindingHolder
class FollowRequestsHeaderAdapter(private val instanceName: String, private val accountLocked: Boolean) : RecyclerView.Adapter<HeaderViewHolder>() { class FollowRequestsHeaderAdapter(
private val instanceName: String,
private val accountLocked: Boolean
) : RecyclerView.Adapter<BindingHolder<ItemFollowRequestsHeaderBinding>>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): HeaderViewHolder { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BindingHolder<ItemFollowRequestsHeaderBinding> {
val view = LayoutInflater.from(parent.context) val binding = ItemFollowRequestsHeaderBinding.inflate(LayoutInflater.from(parent.context), parent, false)
.inflate(R.layout.item_follow_requests_header, parent, false) as TextView return BindingHolder(binding)
return HeaderViewHolder(view)
} }
override fun onBindViewHolder(viewHolder: HeaderViewHolder, position: Int) { override fun onBindViewHolder(viewHolder: BindingHolder<ItemFollowRequestsHeaderBinding>, position: Int) {
viewHolder.textView.text = viewHolder.textView.context.getString(R.string.follow_requests_info, instanceName) viewHolder.binding.root.text = viewHolder.binding.root.context.getString(R.string.follow_requests_info, instanceName)
} }
override fun getItemCount() = if (accountLocked) 0 else 1 override fun getItemCount() = if (accountLocked) 0 else 1
} }
class HeaderViewHolder(var textView: TextView) : RecyclerView.ViewHolder(textView)

View File

@ -1,4 +1,19 @@
package com.keylesspalace.tusky.adapter /* Copyright 2023 Tusky Contributors
*
* This file is a part of Tusky.
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
* License, or (at your option) any later version.
*
* Tusky is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License along with Tusky; if not,
* see <http://www.gnu.org/licenses>. */
package com.keylesspalace.tusky.components.accountlist.adapter
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.ViewGroup import android.view.ViewGroup
@ -9,22 +24,21 @@ import com.keylesspalace.tusky.interfaces.AccountActionListener
import com.keylesspalace.tusky.util.BindingHolder 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
import com.keylesspalace.tusky.util.visible
/** /** Displays a list of muted accounts with mute/unmute account button and mute/unmute notifications switch */
* Displays a list of muted accounts with mute/unmute account and mute/unmute notifications
* buttons.
* */
class MutesAdapter( class MutesAdapter(
accountActionListener: AccountActionListener, accountActionListener: AccountActionListener,
animateAvatar: Boolean, animateAvatar: Boolean,
animateEmojis: Boolean, animateEmojis: Boolean,
showBotOverlay: Boolean showBotOverlay: Boolean
) : AccountAdapter<BindingHolder<ItemMutedUserBinding>>( ) : AccountAdapter<BindingHolder<ItemMutedUserBinding>>(
accountActionListener, accountActionListener = accountActionListener,
animateAvatar, animateAvatar = animateAvatar,
animateEmojis, animateEmojis = animateEmojis,
showBotOverlay showBotOverlay = showBotOverlay
) { ) {
private val mutingNotificationsMap = HashMap<String, Boolean>() private val mutingNotificationsMap = HashMap<String, Boolean>()
override fun createAccountViewHolder(parent: ViewGroup): BindingHolder<ItemMutedUserBinding> { override fun createAccountViewHolder(parent: ViewGroup): BindingHolder<ItemMutedUserBinding> {
@ -48,6 +62,8 @@ class MutesAdapter(
val avatarRadius = context.resources.getDimensionPixelSize(R.dimen.avatar_radius_48dp) val avatarRadius = context.resources.getDimensionPixelSize(R.dimen.avatar_radius_48dp)
loadAvatar(account.avatar, binding.mutedUserAvatar, avatarRadius, animateAvatar) loadAvatar(account.avatar, binding.mutedUserAvatar, avatarRadius, animateAvatar)
binding.mutedUserBotBadge.visible(showBotOverlay && account.bot)
val unmuteString = context.getString(R.string.action_unmute_desc, formattedUsername) val unmuteString = context.getString(R.string.action_unmute_desc, formattedUsername)
binding.mutedUserUnmute.contentDescription = unmuteString binding.mutedUserUnmute.contentDescription = unmuteString
ViewCompat.setTooltipText(binding.mutedUserUnmute, unmuteString) ViewCompat.setTooltipText(binding.mutedUserUnmute, unmuteString)

View File

@ -24,7 +24,6 @@ import androidx.annotation.DrawableRes
import androidx.preference.PreferenceFragmentCompat import androidx.preference.PreferenceFragmentCompat
import com.google.android.material.color.MaterialColors import com.google.android.material.color.MaterialColors
import com.google.android.material.snackbar.Snackbar import com.google.android.material.snackbar.Snackbar
import com.keylesspalace.tusky.AccountListActivity
import com.keylesspalace.tusky.BaseActivity import com.keylesspalace.tusky.BaseActivity
import com.keylesspalace.tusky.BuildConfig import com.keylesspalace.tusky.BuildConfig
import com.keylesspalace.tusky.FiltersActivity import com.keylesspalace.tusky.FiltersActivity
@ -32,6 +31,7 @@ import com.keylesspalace.tusky.R
import com.keylesspalace.tusky.TabPreferenceActivity import com.keylesspalace.tusky.TabPreferenceActivity
import com.keylesspalace.tusky.appstore.EventHub import com.keylesspalace.tusky.appstore.EventHub
import com.keylesspalace.tusky.appstore.PreferenceChangedEvent import com.keylesspalace.tusky.appstore.PreferenceChangedEvent
import com.keylesspalace.tusky.components.accountlist.AccountListActivity
import com.keylesspalace.tusky.components.followedtags.FollowedTagsActivity import com.keylesspalace.tusky.components.followedtags.FollowedTagsActivity
import com.keylesspalace.tusky.components.instancemute.InstanceListActivity import com.keylesspalace.tusky.components.instancemute.InstanceListActivity
import com.keylesspalace.tusky.components.login.LoginActivity import com.keylesspalace.tusky.components.login.LoginActivity

View File

@ -34,14 +34,14 @@ import androidx.recyclerview.widget.SimpleItemAnimator
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout.OnRefreshListener import androidx.swiperefreshlayout.widget.SwipeRefreshLayout.OnRefreshListener
import at.connyduck.sparkbutton.helpers.Utils import at.connyduck.sparkbutton.helpers.Utils
import autodispose2.androidx.lifecycle.autoDispose import autodispose2.androidx.lifecycle.autoDispose
import com.keylesspalace.tusky.AccountListActivity
import com.keylesspalace.tusky.AccountListActivity.Companion.newIntent
import com.keylesspalace.tusky.BaseActivity import com.keylesspalace.tusky.BaseActivity
import com.keylesspalace.tusky.R import com.keylesspalace.tusky.R
import com.keylesspalace.tusky.adapter.StatusBaseViewHolder import com.keylesspalace.tusky.adapter.StatusBaseViewHolder
import com.keylesspalace.tusky.appstore.EventHub import com.keylesspalace.tusky.appstore.EventHub
import com.keylesspalace.tusky.appstore.PreferenceChangedEvent import com.keylesspalace.tusky.appstore.PreferenceChangedEvent
import com.keylesspalace.tusky.appstore.StatusComposedEvent import com.keylesspalace.tusky.appstore.StatusComposedEvent
import com.keylesspalace.tusky.components.accountlist.AccountListActivity
import com.keylesspalace.tusky.components.accountlist.AccountListActivity.Companion.newIntent
import com.keylesspalace.tusky.components.preference.PreferencesFragment.ReadingOrder import com.keylesspalace.tusky.components.preference.PreferencesFragment.ReadingOrder
import com.keylesspalace.tusky.components.timeline.viewmodel.CachedTimelineViewModel import com.keylesspalace.tusky.components.timeline.viewmodel.CachedTimelineViewModel
import com.keylesspalace.tusky.components.timeline.viewmodel.NetworkTimelineViewModel import com.keylesspalace.tusky.components.timeline.viewmodel.NetworkTimelineViewModel

View File

@ -32,10 +32,10 @@ import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.SimpleItemAnimator import androidx.recyclerview.widget.SimpleItemAnimator
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout.OnRefreshListener import androidx.swiperefreshlayout.widget.SwipeRefreshLayout.OnRefreshListener
import com.google.android.material.snackbar.Snackbar import com.google.android.material.snackbar.Snackbar
import com.keylesspalace.tusky.AccountListActivity
import com.keylesspalace.tusky.AccountListActivity.Companion.newIntent
import com.keylesspalace.tusky.BaseActivity import com.keylesspalace.tusky.BaseActivity
import com.keylesspalace.tusky.R import com.keylesspalace.tusky.R
import com.keylesspalace.tusky.components.accountlist.AccountListActivity
import com.keylesspalace.tusky.components.accountlist.AccountListActivity.Companion.newIntent
import com.keylesspalace.tusky.components.viewthread.edits.ViewEditsFragment import com.keylesspalace.tusky.components.viewthread.edits.ViewEditsFragment
import com.keylesspalace.tusky.databinding.FragmentViewThreadBinding import com.keylesspalace.tusky.databinding.FragmentViewThreadBinding
import com.keylesspalace.tusky.di.Injectable import com.keylesspalace.tusky.di.Injectable

View File

@ -16,7 +16,6 @@
package com.keylesspalace.tusky.di package com.keylesspalace.tusky.di
import com.keylesspalace.tusky.AboutActivity import com.keylesspalace.tusky.AboutActivity
import com.keylesspalace.tusky.AccountListActivity
import com.keylesspalace.tusky.BaseActivity import com.keylesspalace.tusky.BaseActivity
import com.keylesspalace.tusky.EditProfileActivity import com.keylesspalace.tusky.EditProfileActivity
import com.keylesspalace.tusky.FiltersActivity import com.keylesspalace.tusky.FiltersActivity
@ -28,6 +27,7 @@ import com.keylesspalace.tusky.StatusListActivity
import com.keylesspalace.tusky.TabPreferenceActivity import com.keylesspalace.tusky.TabPreferenceActivity
import com.keylesspalace.tusky.ViewMediaActivity import com.keylesspalace.tusky.ViewMediaActivity
import com.keylesspalace.tusky.components.account.AccountActivity import com.keylesspalace.tusky.components.account.AccountActivity
import com.keylesspalace.tusky.components.accountlist.AccountListActivity
import com.keylesspalace.tusky.components.announcements.AnnouncementsActivity import com.keylesspalace.tusky.components.announcements.AnnouncementsActivity
import com.keylesspalace.tusky.components.compose.ComposeActivity import com.keylesspalace.tusky.components.compose.ComposeActivity
import com.keylesspalace.tusky.components.drafts.DraftsActivity import com.keylesspalace.tusky.components.drafts.DraftsActivity

View File

@ -18,6 +18,7 @@ package com.keylesspalace.tusky.di
import com.keylesspalace.tusky.AccountsInListFragment import com.keylesspalace.tusky.AccountsInListFragment
import com.keylesspalace.tusky.components.account.list.ListsForAccountFragment import com.keylesspalace.tusky.components.account.list.ListsForAccountFragment
import com.keylesspalace.tusky.components.account.media.AccountMediaFragment import com.keylesspalace.tusky.components.account.media.AccountMediaFragment
import com.keylesspalace.tusky.components.accountlist.AccountListFragment
import com.keylesspalace.tusky.components.conversation.ConversationsFragment import com.keylesspalace.tusky.components.conversation.ConversationsFragment
import com.keylesspalace.tusky.components.instancemute.fragment.InstanceListFragment import com.keylesspalace.tusky.components.instancemute.fragment.InstanceListFragment
import com.keylesspalace.tusky.components.preference.AccountPreferencesFragment import com.keylesspalace.tusky.components.preference.AccountPreferencesFragment
@ -32,7 +33,6 @@ import com.keylesspalace.tusky.components.search.fragments.SearchStatusesFragmen
import com.keylesspalace.tusky.components.timeline.TimelineFragment import com.keylesspalace.tusky.components.timeline.TimelineFragment
import com.keylesspalace.tusky.components.viewthread.ViewThreadFragment import com.keylesspalace.tusky.components.viewthread.ViewThreadFragment
import com.keylesspalace.tusky.components.viewthread.edits.ViewEditsFragment import com.keylesspalace.tusky.components.viewthread.edits.ViewEditsFragment
import com.keylesspalace.tusky.fragment.AccountListFragment
import com.keylesspalace.tusky.fragment.NotificationsFragment import com.keylesspalace.tusky.fragment.NotificationsFragment
import dagger.Module import dagger.Module
import dagger.android.ContributesAndroidInjector import dagger.android.ContributesAndroidInjector

View File

@ -4,7 +4,7 @@
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
tools:context="com.keylesspalace.tusky.AccountListActivity"> tools:context="com.keylesspalace.tusky.components.accountlist.AccountListActivity">
<include <include
android:id="@+id/includedToolbar" android:id="@+id/includedToolbar"

View File

@ -4,8 +4,8 @@
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/account_container" android:id="@+id/account_container"
android:layout_width="match_parent" android:layout_width="match_parent"
android:background="?attr/selectableItemBackground"
android:layout_height="72dp" android:layout_height="72dp"
android:background="?attr/selectableItemBackground"
android:paddingStart="16dp" android:paddingStart="16dp"
android:paddingEnd="16dp"> android:paddingEnd="16dp">
@ -14,6 +14,7 @@
android:layout_width="48dp" android:layout_width="48dp"
android:layout_height="48dp" android:layout_height="48dp"
android:layout_marginEnd="24dp" android:layout_marginEnd="24dp"
android:contentDescription="@string/action_view_profile"
android:foregroundGravity="center_vertical" android:foregroundGravity="center_vertical"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
@ -26,8 +27,8 @@
android:layout_height="24dp" android:layout_height="24dp"
android:contentDescription="@null" android:contentDescription="@null"
android:importantForAccessibility="no" android:importantForAccessibility="no"
android:visibility="gone"
android:src="@drawable/bot_badge" android:src="@drawable/bot_badge"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="@id/account_avatar" app:layout_constraintBottom_toBottomOf="@id/account_avatar"
app:layout_constraintEnd_toEndOf="@id/account_avatar" app:layout_constraintEnd_toEndOf="@id/account_avatar"
tools:src="#000" tools:src="#000"

View File

@ -1,21 +1,62 @@
<?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="72dp"
android:gravity="center_vertical" android:gravity="center_vertical"
android:paddingLeft="16dp" android:paddingStart="16dp"
android:paddingRight="16dp"> android:paddingEnd="16dp">
<ImageView <ImageView
android:id="@+id/blocked_user_avatar" android:id="@+id/blocked_user_avatar"
android:layout_width="48dp" android:layout_width="48dp"
android:layout_height="48dp" android:layout_height="48dp"
android:layout_alignParentStart="true" android:contentDescription="@string/action_view_profile"
android:layout_centerVertical="true" app:layout_constraintBottom_toBottomOf="parent"
android:layout_marginEnd="24dp" app:layout_constraintStart_toStartOf="parent"
android:contentDescription="@string/action_view_profile" /> app:layout_constraintTop_toTopOf="parent"
tools:src="@drawable/avatar_default" />
<ImageView
android:id="@+id/blocked_user_bot_badge"
android:layout_width="24dp"
android:layout_height="24dp"
android:contentDescription="@string/profile_badge_bot_text"
android:src="@drawable/bot_badge"
app:layout_constraintBottom_toBottomOf="@id/blocked_user_avatar"
app:layout_constraintEnd_toEndOf="@id/blocked_user_avatar" />
<TextView
android:id="@+id/blocked_user_display_name"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="14dp"
android:ellipsize="end"
android:maxLines="1"
android:textColor="?android:textColorPrimary"
android:textSize="?attr/status_text_large"
android:textStyle="normal|bold"
app:layout_constraintBottom_toTopOf="@id/blocked_user_username"
app:layout_constraintEnd_toStartOf="@id/blocked_user_unblock"
app:layout_constraintStart_toEndOf="@id/blocked_user_avatar"
app:layout_constraintTop_toTopOf="@id/blocked_user_avatar"
tools:text="Display name" />
<TextView
android:id="@+id/blocked_user_username"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="14dp"
android:ellipsize="end"
android:maxLines="1"
android:textColor="?android:textColorSecondary"
android:textSize="?attr/status_text_medium"
app:layout_constraintBottom_toBottomOf="@id/blocked_user_avatar"
app:layout_constraintEnd_toStartOf="@id/blocked_user_unblock"
app:layout_constraintStart_toEndOf="@id/blocked_user_avatar"
app:layout_constraintTop_toBottomOf="@id/blocked_user_display_name"
tools:text="\@username" />
<ImageButton <ImageButton
android:id="@+id/blocked_user_unblock" android:id="@+id/blocked_user_unblock"
@ -28,37 +69,9 @@
android:background="?attr/selectableItemBackgroundBorderless" android:background="?attr/selectableItemBackgroundBorderless"
android:contentDescription="@string/action_unblock" android:contentDescription="@string/action_unblock"
android:padding="4dp" android:padding="4dp"
app:layout_constraintBottom_toBottomOf="@id/blocked_user_avatar"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@id/blocked_user_avatar"
app:srcCompat="@drawable/ic_clear_24dp" /> app:srcCompat="@drawable/ic_clear_24dp" />
<LinearLayout </androidx.constraintlayout.widget.ConstraintLayout>
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_toEndOf="@id/blocked_user_avatar"
android:layout_toStartOf="@id/blocked_user_unblock"
android:gravity="center_vertical"
android:orientation="vertical">
<TextView
android:id="@+id/blocked_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/blocked_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

@ -35,6 +35,15 @@
app:layout_constraintTop_toBottomOf="@id/notificationTextView" app:layout_constraintTop_toBottomOf="@id/notificationTextView"
tools:src="@drawable/avatar_default" /> tools:src="@drawable/avatar_default" />
<ImageView
android:id="@+id/avatarBadge"
android:layout_width="24dp"
android:layout_height="24dp"
android:contentDescription="@string/profile_badge_bot_text"
android:src="@drawable/bot_badge"
app:layout_constraintBottom_toBottomOf="@id/avatar"
app:layout_constraintEnd_toEndOf="@id/avatar" />
<TextView <TextView
android:id="@+id/displayNameTextView" android:id="@+id/displayNameTextView"
android:layout_width="0dp" android:layout_width="0dp"
@ -97,4 +106,5 @@
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@id/avatar" app:layout_constraintTop_toTopOf="@id/avatar"
app:srcCompat="@drawable/ic_check_24dp" /> app:srcCompat="@drawable/ic_check_24dp" />
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -19,11 +19,20 @@
app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toTopOf="parent"
tools:src="@drawable/avatar_default" /> tools:src="@drawable/avatar_default" />
<ImageView
android:id="@+id/muted_user_bot_badge"
android:layout_width="24dp"
android:layout_height="24dp"
android:contentDescription="@string/profile_badge_bot_text"
android:src="@drawable/bot_badge"
app:layout_constraintBottom_toBottomOf="@id/muted_user_avatar"
app:layout_constraintEnd_toEndOf="@id/muted_user_avatar" />
<TextView <TextView
android:id="@+id/muted_user_display_name" android:id="@+id/muted_user_display_name"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginStart="24dp" android:layout_marginStart="14dp"
android:ellipsize="end" android:ellipsize="end"
android:maxLines="1" android:maxLines="1"
android:textColor="?android:textColorPrimary" android:textColor="?android:textColorPrimary"
@ -65,16 +74,16 @@
tools:ignore="ContentDescription" /> tools:ignore="ContentDescription" />
<com.google.android.material.switchmaterial.SwitchMaterial <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"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginBottom="4dp"
android:textColor="?android:textColorTertiary"
android:layout_marginTop="4dp" android:layout_marginTop="4dp"
android:layout_marginBottom="4dp"
android:text="@string/mute_notifications_switch"
android:textColor="?android:textColorTertiary"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:switchPadding="4dp"
app:layout_constraintStart_toStartOf="@id/muted_user_display_name" app:layout_constraintStart_toStartOf="@id/muted_user_display_name"
app:layout_constraintTop_toBottomOf="@id/muted_user_username" /> app:layout_constraintTop_toBottomOf="@id/muted_user_username"
app:switchPadding="4dp" />
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -10,6 +10,7 @@ import androidx.viewpager2.widget.ViewPager2
import androidx.work.testing.WorkManagerTestInitHelper import androidx.work.testing.WorkManagerTestInitHelper
import at.connyduck.calladapter.networkresult.NetworkResult import at.connyduck.calladapter.networkresult.NetworkResult
import com.keylesspalace.tusky.appstore.EventHub import com.keylesspalace.tusky.appstore.EventHub
import com.keylesspalace.tusky.components.accountlist.AccountListActivity
import com.keylesspalace.tusky.components.notifications.NotificationHelper import com.keylesspalace.tusky.components.notifications.NotificationHelper
import com.keylesspalace.tusky.db.AccountEntity import com.keylesspalace.tusky.db.AccountEntity
import com.keylesspalace.tusky.entity.Account import com.keylesspalace.tusky.entity.Account