migrating to ViewBinding part 4: Adapters (#2095)
This commit is contained in:
parent
22bed19d90
commit
fc4b47aee4
27 changed files with 424 additions and 543 deletions
|
@ -19,60 +19,57 @@ import android.text.method.LinkMovementMethod
|
|||
import androidx.recyclerview.widget.RecyclerView
|
||||
import android.view.LayoutInflater
|
||||
import android.view.ViewGroup
|
||||
import android.view.View
|
||||
import android.widget.TextView
|
||||
import com.keylesspalace.tusky.R
|
||||
import com.keylesspalace.tusky.databinding.ItemAccountFieldBinding
|
||||
import com.keylesspalace.tusky.entity.Emoji
|
||||
import com.keylesspalace.tusky.entity.Field
|
||||
import com.keylesspalace.tusky.entity.IdentityProof
|
||||
import com.keylesspalace.tusky.interfaces.LinkListener
|
||||
import com.keylesspalace.tusky.util.*
|
||||
import kotlinx.android.synthetic.main.item_account_field.view.*
|
||||
|
||||
class AccountFieldAdapter(private val linkListener: LinkListener, private val animateEmojis: Boolean) : RecyclerView.Adapter<AccountFieldAdapter.ViewHolder>() {
|
||||
class AccountFieldAdapter(
|
||||
private val linkListener: LinkListener,
|
||||
private val animateEmojis: Boolean
|
||||
) : RecyclerView.Adapter<BindingHolder<ItemAccountFieldBinding>>() {
|
||||
|
||||
var emojis: List<Emoji> = emptyList()
|
||||
var fields: List<Either<IdentityProof, Field>> = emptyList()
|
||||
|
||||
override fun getItemCount() = fields.size
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
||||
val view = LayoutInflater.from(parent.context).inflate(R.layout.item_account_field, parent, false)
|
||||
return ViewHolder(view)
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BindingHolder<ItemAccountFieldBinding> {
|
||||
val binding = ItemAccountFieldBinding.inflate(LayoutInflater.from(parent.context), parent, false)
|
||||
return BindingHolder(binding)
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(viewHolder: ViewHolder, position: Int) {
|
||||
override fun onBindViewHolder(holder: BindingHolder<ItemAccountFieldBinding>, position: Int) {
|
||||
val proofOrField = fields[position]
|
||||
val nameTextView = holder.binding.accountFieldName
|
||||
val valueTextView = holder.binding.accountFieldValue
|
||||
|
||||
if(proofOrField.isLeft()) {
|
||||
val identityProof = proofOrField.asLeft()
|
||||
|
||||
viewHolder.nameTextView.text = identityProof.provider
|
||||
viewHolder.valueTextView.text = LinkHelper.createClickableText(identityProof.username, identityProof.profileUrl)
|
||||
nameTextView.text = identityProof.provider
|
||||
valueTextView.text = LinkHelper.createClickableText(identityProof.username, identityProof.profileUrl)
|
||||
|
||||
viewHolder.valueTextView.movementMethod = LinkMovementMethod.getInstance()
|
||||
valueTextView.movementMethod = LinkMovementMethod.getInstance()
|
||||
|
||||
viewHolder.valueTextView.setCompoundDrawablesRelativeWithIntrinsicBounds(0, 0, R.drawable.ic_check_circle, 0)
|
||||
valueTextView.setCompoundDrawablesRelativeWithIntrinsicBounds(0, 0, R.drawable.ic_check_circle, 0)
|
||||
} else {
|
||||
val field = proofOrField.asRight()
|
||||
val emojifiedName = field.name.emojify(emojis, viewHolder.nameTextView, animateEmojis)
|
||||
viewHolder.nameTextView.text = emojifiedName
|
||||
val emojifiedName = field.name.emojify(emojis, nameTextView, animateEmojis)
|
||||
nameTextView.text = emojifiedName
|
||||
|
||||
val emojifiedValue = field.value.emojify(emojis, viewHolder.valueTextView, animateEmojis)
|
||||
LinkHelper.setClickableText(viewHolder.valueTextView, emojifiedValue, null, linkListener)
|
||||
val emojifiedValue = field.value.emojify(emojis, valueTextView, animateEmojis)
|
||||
LinkHelper.setClickableText(valueTextView, emojifiedValue, null, linkListener)
|
||||
|
||||
if(field.verifiedAt != null) {
|
||||
viewHolder.valueTextView.setCompoundDrawablesRelativeWithIntrinsicBounds(0, 0, R.drawable.ic_check_circle, 0)
|
||||
valueTextView.setCompoundDrawablesRelativeWithIntrinsicBounds(0, 0, R.drawable.ic_check_circle, 0)
|
||||
} else {
|
||||
viewHolder.valueTextView.setCompoundDrawablesRelativeWithIntrinsicBounds(0, 0, 0, 0 )
|
||||
valueTextView.setCompoundDrawablesRelativeWithIntrinsicBounds(0, 0, 0, 0 )
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class ViewHolder(rootView: View) : RecyclerView.ViewHolder(rootView) {
|
||||
val nameTextView: TextView = rootView.accountFieldName
|
||||
val valueTextView: TextView = rootView.accountFieldValue
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -15,18 +15,16 @@
|
|||
|
||||
package com.keylesspalace.tusky.adapter
|
||||
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import android.text.Editable
|
||||
import android.text.TextWatcher
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.EditText
|
||||
import com.keylesspalace.tusky.R
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.keylesspalace.tusky.databinding.ItemEditFieldBinding
|
||||
import com.keylesspalace.tusky.entity.StringField
|
||||
import kotlinx.android.synthetic.main.item_edit_field.view.*
|
||||
import com.keylesspalace.tusky.util.BindingHolder
|
||||
|
||||
class AccountFieldEditAdapter : RecyclerView.Adapter<AccountFieldEditAdapter.ViewHolder>() {
|
||||
class AccountFieldEditAdapter : RecyclerView.Adapter<BindingHolder<ItemEditFieldBinding>>() {
|
||||
|
||||
private val fieldData = mutableListOf<MutableStringPair>()
|
||||
|
||||
|
@ -54,20 +52,20 @@ class AccountFieldEditAdapter : RecyclerView.Adapter<AccountFieldEditAdapter.Vie
|
|||
notifyItemInserted(fieldData.size - 1)
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int = fieldData.size
|
||||
override fun getItemCount() = fieldData.size
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
||||
val view = LayoutInflater.from(parent.context).inflate(R.layout.item_edit_field, parent, false)
|
||||
return ViewHolder(view)
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BindingHolder<ItemEditFieldBinding> {
|
||||
val binding = ItemEditFieldBinding.inflate(LayoutInflater.from(parent.context), parent, false)
|
||||
return BindingHolder(binding)
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(viewHolder: ViewHolder, position: Int) {
|
||||
viewHolder.nameTextView.setText(fieldData[position].first)
|
||||
viewHolder.valueTextView.setText(fieldData[position].second)
|
||||
override fun onBindViewHolder(holder: BindingHolder<ItemEditFieldBinding>, position: Int) {
|
||||
holder.binding.accountFieldName.setText(fieldData[position].first)
|
||||
holder.binding.accountFieldValue.setText(fieldData[position].second)
|
||||
|
||||
viewHolder.nameTextView.addTextChangedListener(object: TextWatcher {
|
||||
holder.binding.accountFieldName.addTextChangedListener(object: TextWatcher {
|
||||
override fun afterTextChanged(newText: Editable) {
|
||||
fieldData[viewHolder.adapterPosition].first = newText.toString()
|
||||
fieldData[holder.adapterPosition].first = newText.toString()
|
||||
}
|
||||
|
||||
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {}
|
||||
|
@ -75,9 +73,9 @@ class AccountFieldEditAdapter : RecyclerView.Adapter<AccountFieldEditAdapter.Vie
|
|||
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {}
|
||||
})
|
||||
|
||||
viewHolder.valueTextView.addTextChangedListener(object: TextWatcher {
|
||||
holder.binding.accountFieldValue.addTextChangedListener(object: TextWatcher {
|
||||
override fun afterTextChanged(newText: Editable) {
|
||||
fieldData[viewHolder.adapterPosition].second = newText.toString()
|
||||
fieldData[holder.adapterPosition].second = newText.toString()
|
||||
}
|
||||
|
||||
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {}
|
||||
|
@ -87,12 +85,6 @@ class AccountFieldEditAdapter : RecyclerView.Adapter<AccountFieldEditAdapter.Vie
|
|||
|
||||
}
|
||||
|
||||
class ViewHolder(rootView: View) : RecyclerView.ViewHolder(rootView) {
|
||||
val nameTextView: EditText = rootView.accountFieldName
|
||||
val valueTextView: EditText = rootView.accountFieldValue
|
||||
}
|
||||
|
||||
class MutableStringPair (var first: String, var second: String)
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -22,39 +22,35 @@ import android.view.ViewGroup
|
|||
import android.widget.ArrayAdapter
|
||||
import androidx.preference.PreferenceManager
|
||||
import com.keylesspalace.tusky.R
|
||||
import com.keylesspalace.tusky.databinding.ItemAutocompleteAccountBinding
|
||||
import com.keylesspalace.tusky.db.AccountEntity
|
||||
import com.keylesspalace.tusky.settings.PrefKeys
|
||||
import com.keylesspalace.tusky.util.*
|
||||
import kotlinx.android.synthetic.main.item_autocomplete_account.view.*
|
||||
|
||||
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
|
||||
|
||||
if (convertView == null) {
|
||||
val layoutInflater = context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
|
||||
view = layoutInflater.inflate(R.layout.item_autocomplete_account, parent, false)
|
||||
override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
|
||||
val binding = if (convertView == null) {
|
||||
ItemAutocompleteAccountBinding.inflate(LayoutInflater.from(context), parent, false)
|
||||
} else {
|
||||
ItemAutocompleteAccountBinding.bind(convertView)
|
||||
}
|
||||
view!!
|
||||
|
||||
val account = getItem(position)
|
||||
if (account != null) {
|
||||
val username = view.username
|
||||
val displayName = view.display_name
|
||||
val avatar = view.avatar
|
||||
val pm = PreferenceManager.getDefaultSharedPreferences(avatar.context)
|
||||
val pm = PreferenceManager.getDefaultSharedPreferences(binding.avatar.context)
|
||||
val animateEmojis = pm.getBoolean(PrefKeys.ANIMATE_CUSTOM_EMOJIS, false)
|
||||
|
||||
username.text = account.fullName
|
||||
displayName.text = account.displayName.emojify(account.emojis, displayName, animateEmojis)
|
||||
binding.username.text = account.fullName
|
||||
binding.displayName.text = account.displayName.emojify(account.emojis, binding.displayName, animateEmojis)
|
||||
|
||||
val avatarRadius = avatar.context.resources.getDimensionPixelSize(R.dimen.avatar_radius_42dp)
|
||||
val avatarRadius = context.resources.getDimensionPixelSize(R.dimen.avatar_radius_42dp)
|
||||
val animateAvatar = pm.getBoolean("animateGifAvatars", false)
|
||||
|
||||
loadAvatar(account.profilePictureUrl, avatar, avatarRadius, animateAvatar)
|
||||
loadAvatar(account.profilePictureUrl, binding.avatar, avatarRadius, animateAvatar)
|
||||
|
||||
}
|
||||
|
||||
return view
|
||||
return binding.root
|
||||
}
|
||||
}
|
|
@ -15,48 +15,44 @@
|
|||
|
||||
package com.keylesspalace.tusky.adapter
|
||||
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import android.view.LayoutInflater
|
||||
import android.view.ViewGroup
|
||||
import android.widget.ImageView
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.bumptech.glide.Glide
|
||||
import com.keylesspalace.tusky.R
|
||||
import com.keylesspalace.tusky.databinding.ItemEmojiButtonBinding
|
||||
import com.keylesspalace.tusky.entity.Emoji
|
||||
import com.keylesspalace.tusky.util.BindingHolder
|
||||
import java.util.*
|
||||
|
||||
class EmojiAdapter(emojiList: List<Emoji>, private val onEmojiSelectedListener: OnEmojiSelectedListener) : RecyclerView.Adapter<EmojiAdapter.EmojiHolder>() {
|
||||
private val emojiList : List<Emoji>
|
||||
class EmojiAdapter(
|
||||
emojiList: List<Emoji>,
|
||||
private val onEmojiSelectedListener: OnEmojiSelectedListener
|
||||
) : RecyclerView.Adapter<BindingHolder<ItemEmojiButtonBinding>>() {
|
||||
|
||||
init {
|
||||
this.emojiList = emojiList.filter { emoji -> emoji.visibleInPicker == null || emoji.visibleInPicker }
|
||||
.sortedBy { it.shortcode.toLowerCase(Locale.ROOT) }
|
||||
private val emojiList : List<Emoji> = emojiList.filter { emoji -> emoji.visibleInPicker == null || emoji.visibleInPicker }
|
||||
.sortedBy { it.shortcode.toLowerCase(Locale.ROOT) }
|
||||
|
||||
override fun getItemCount() = emojiList.size
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BindingHolder<ItemEmojiButtonBinding> {
|
||||
val binding = ItemEmojiButtonBinding.inflate(LayoutInflater.from(parent.context), parent, false)
|
||||
return BindingHolder(binding)
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int {
|
||||
return emojiList.size
|
||||
}
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): EmojiHolder {
|
||||
val view = LayoutInflater.from(parent.context).inflate(R.layout.item_emoji_button, parent, false) as ImageView
|
||||
return EmojiHolder(view)
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(viewHolder: EmojiHolder, position: Int) {
|
||||
override fun onBindViewHolder(holder: BindingHolder<ItemEmojiButtonBinding>, position: Int) {
|
||||
val emoji = emojiList[position]
|
||||
val emojiImageView = holder.binding.root
|
||||
|
||||
Glide.with(viewHolder.emojiImageView)
|
||||
Glide.with(emojiImageView)
|
||||
.load(emoji.url)
|
||||
.into(viewHolder.emojiImageView)
|
||||
.into(emojiImageView)
|
||||
|
||||
viewHolder.emojiImageView.setOnClickListener {
|
||||
emojiImageView.setOnClickListener {
|
||||
onEmojiSelectedListener.onEmojiSelected(emoji.shortcode)
|
||||
}
|
||||
|
||||
viewHolder.emojiImageView.contentDescription = emoji.shortcode
|
||||
emojiImageView.contentDescription = emoji.shortcode
|
||||
}
|
||||
|
||||
class EmojiHolder(val emojiImageView: ImageView) : RecyclerView.ViewHolder(emojiImageView)
|
||||
|
||||
}
|
||||
|
||||
interface OnEmojiSelectedListener {
|
||||
|
|
|
@ -1,55 +1,67 @@
|
|||
/* Copyright 2021 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.adapter
|
||||
|
||||
import android.graphics.Typeface
|
||||
import android.text.SpannableStringBuilder
|
||||
import android.text.Spanned
|
||||
import android.text.style.StyleSpan
|
||||
import android.view.View
|
||||
import androidx.preference.PreferenceManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.keylesspalace.tusky.R
|
||||
import com.keylesspalace.tusky.databinding.ItemFollowRequestBinding
|
||||
import com.keylesspalace.tusky.entity.Account
|
||||
import com.keylesspalace.tusky.interfaces.AccountActionListener
|
||||
import com.keylesspalace.tusky.util.*
|
||||
import kotlinx.android.synthetic.main.item_follow_request_notification.view.*
|
||||
|
||||
internal class FollowRequestViewHolder(
|
||||
itemView: View,
|
||||
private val showHeader: Boolean) : RecyclerView.ViewHolder(itemView) {
|
||||
private var id: String? = null
|
||||
class FollowRequestViewHolder(
|
||||
private val binding: ItemFollowRequestBinding,
|
||||
private val showHeader: Boolean
|
||||
) : RecyclerView.ViewHolder(binding.root) {
|
||||
|
||||
fun setupWithAccount(account: Account, animateAvatar: Boolean, animateEmojis: Boolean) {
|
||||
id = account.id
|
||||
val wrappedName = account.name.unicodeWrap()
|
||||
val emojifiedName: CharSequence = wrappedName.emojify(account.emojis, itemView, animateEmojis)
|
||||
itemView.displayNameTextView.text = emojifiedName
|
||||
binding.displayNameTextView.text = emojifiedName
|
||||
if (showHeader) {
|
||||
val wholeMessage: String = itemView.context.getString(R.string.notification_follow_request_format, wrappedName)
|
||||
itemView.notificationTextView?.text = SpannableStringBuilder(wholeMessage).apply {
|
||||
binding.notificationTextView.text = SpannableStringBuilder(wholeMessage).apply {
|
||||
setSpan(StyleSpan(Typeface.BOLD), 0, wrappedName.length, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
|
||||
}.emojify(account.emojis, itemView, animateEmojis)
|
||||
}
|
||||
itemView.notificationTextView?.visible(showHeader)
|
||||
binding.notificationTextView.visible(showHeader)
|
||||
val format = itemView.context.getString(R.string.status_username_format)
|
||||
val formattedUsername = String.format(format, account.username)
|
||||
itemView.usernameTextView.text = formattedUsername
|
||||
val avatarRadius = itemView.avatar.context.resources.getDimensionPixelSize(R.dimen.avatar_radius_48dp)
|
||||
loadAvatar(account.avatar, itemView.avatar, avatarRadius, animateAvatar)
|
||||
binding.usernameTextView.text = formattedUsername
|
||||
val avatarRadius = binding.avatar.context.resources.getDimensionPixelSize(R.dimen.avatar_radius_48dp)
|
||||
loadAvatar(account.avatar, binding.avatar, avatarRadius, animateAvatar)
|
||||
}
|
||||
|
||||
fun setupActionListener(listener: AccountActionListener) {
|
||||
itemView.acceptButton.setOnClickListener {
|
||||
fun setupActionListener(listener: AccountActionListener, accountId: String) {
|
||||
binding.acceptButton.setOnClickListener {
|
||||
val position = adapterPosition
|
||||
if (position != RecyclerView.NO_POSITION) {
|
||||
listener.onRespondToFollowRequest(true, id, position)
|
||||
listener.onRespondToFollowRequest(true, accountId, position)
|
||||
}
|
||||
}
|
||||
itemView.rejectButton.setOnClickListener {
|
||||
binding.rejectButton.setOnClickListener {
|
||||
val position = adapterPosition
|
||||
if (position != RecyclerView.NO_POSITION) {
|
||||
listener.onRespondToFollowRequest(false, id, position)
|
||||
listener.onRespondToFollowRequest(false, accountId, position)
|
||||
}
|
||||
}
|
||||
itemView.setOnClickListener { listener.onViewAccount(id) }
|
||||
itemView.setOnClickListener { listener.onViewAccount(accountId) }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@ import androidx.annotation.NonNull;
|
|||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.keylesspalace.tusky.R;
|
||||
import com.keylesspalace.tusky.databinding.ItemFollowRequestBinding;
|
||||
import com.keylesspalace.tusky.interfaces.AccountActionListener;
|
||||
|
||||
public class FollowRequestsAdapter extends AccountAdapter {
|
||||
|
@ -37,9 +38,8 @@ public class FollowRequestsAdapter extends AccountAdapter {
|
|||
switch (viewType) {
|
||||
default:
|
||||
case VIEW_TYPE_ACCOUNT: {
|
||||
View view = LayoutInflater.from(parent.getContext())
|
||||
.inflate(R.layout.item_follow_request, parent, false);
|
||||
return new FollowRequestViewHolder(view, false);
|
||||
ItemFollowRequestBinding binding = ItemFollowRequestBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false);
|
||||
return new FollowRequestViewHolder(binding, false);
|
||||
}
|
||||
case VIEW_TYPE_FOOTER: {
|
||||
View view = LayoutInflater.from(parent.getContext())
|
||||
|
@ -54,7 +54,7 @@ public class FollowRequestsAdapter extends AccountAdapter {
|
|||
if (getItemViewType(position) == VIEW_TYPE_ACCOUNT) {
|
||||
FollowRequestViewHolder holder = (FollowRequestViewHolder) viewHolder;
|
||||
holder.setupWithAccount(accountList.get(position), animateAvatar, animateEmojis);
|
||||
holder.setupActionListener(accountActionListener);
|
||||
holder.setupActionListener(accountActionListener, accountList.get(position).getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,16 +0,0 @@
|
|||
package com.keylesspalace.tusky.adapter
|
||||
|
||||
import android.view.View
|
||||
import android.widget.TextView
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.keylesspalace.tusky.R
|
||||
import com.keylesspalace.tusky.interfaces.LinkListener
|
||||
|
||||
class HashtagViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
|
||||
private val hashtag: TextView = itemView.findViewById(R.id.hashtag)
|
||||
|
||||
fun setup(tag: String, listener: LinkListener) {
|
||||
hashtag.text = String.format("#%s", tag)
|
||||
hashtag.setOnClickListener { listener.onViewTag(tag) }
|
||||
}
|
||||
}
|
|
@ -21,21 +21,22 @@ import android.view.View
|
|||
import android.view.ViewGroup
|
||||
import android.widget.ArrayAdapter
|
||||
import com.keylesspalace.tusky.R
|
||||
import com.keylesspalace.tusky.databinding.ItemPickerListBinding
|
||||
import com.keylesspalace.tusky.entity.MastoList
|
||||
import kotlinx.android.synthetic.main.item_picker_list.view.*
|
||||
|
||||
class ListSelectionAdapter(context: Context) : ArrayAdapter<MastoList>(context, R.layout.item_autocomplete_hashtag) {
|
||||
class ListSelectionAdapter(context: Context) : ArrayAdapter<MastoList>(context, R.layout.item_picker_list) {
|
||||
override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
|
||||
|
||||
val layoutInflater = context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
|
||||
|
||||
val view = convertView
|
||||
?: layoutInflater.inflate(R.layout.item_picker_list, parent, false)
|
||||
|
||||
getItem(position)?.let { list ->
|
||||
view.title.text = list.title
|
||||
val binding = if (convertView == null) {
|
||||
ItemPickerListBinding.inflate(LayoutInflater.from(context), parent, false)
|
||||
} else {
|
||||
ItemPickerListBinding.bind(convertView)
|
||||
}
|
||||
|
||||
return view
|
||||
getItem(position)?.let { list ->
|
||||
binding.root.text = list.title
|
||||
}
|
||||
|
||||
return binding.root
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,7 +9,6 @@ import android.widget.TextView;
|
|||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.core.view.ViewCompat;
|
||||
import androidx.preference.PreferenceManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.keylesspalace.tusky.R;
|
||||
|
|
|
@ -16,29 +16,28 @@
|
|||
package com.keylesspalace.tusky.adapter
|
||||
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import com.keylesspalace.tusky.databinding.ItemNetworkStateBinding
|
||||
import com.keylesspalace.tusky.util.NetworkState
|
||||
import com.keylesspalace.tusky.util.Status
|
||||
import com.keylesspalace.tusky.util.visible
|
||||
import kotlinx.android.synthetic.main.item_network_state.view.*
|
||||
|
||||
class NetworkStateViewHolder(itemView: View,
|
||||
class NetworkStateViewHolder(private val binding: ItemNetworkStateBinding,
|
||||
private val retryCallback: () -> Unit)
|
||||
: RecyclerView.ViewHolder(itemView) {
|
||||
: RecyclerView.ViewHolder(binding.root) {
|
||||
|
||||
fun setUpWithNetworkState(state: NetworkState?, fullScreen: Boolean) {
|
||||
itemView.progressBar.visible(state?.status == Status.RUNNING)
|
||||
itemView.retryButton.visible(state?.status == Status.FAILED)
|
||||
itemView.errorMsg.visible(state?.msg != null)
|
||||
itemView.errorMsg.text = state?.msg
|
||||
itemView.retryButton.setOnClickListener {
|
||||
binding.progressBar.visible(state?.status == Status.RUNNING)
|
||||
binding.retryButton.visible(state?.status == Status.FAILED)
|
||||
binding.errorMsg.visible(state?.msg != null)
|
||||
binding.errorMsg.text = state?.msg
|
||||
binding.retryButton.setOnClickListener {
|
||||
retryCallback()
|
||||
}
|
||||
if(fullScreen) {
|
||||
itemView.layoutParams.height = ViewGroup.LayoutParams.MATCH_PARENT
|
||||
binding.root.layoutParams.height = ViewGroup.LayoutParams.MATCH_PARENT
|
||||
} else {
|
||||
itemView.layoutParams.height = ViewGroup.LayoutParams.WRAP_CONTENT
|
||||
binding.root.layoutParams.height = ViewGroup.LayoutParams.WRAP_CONTENT
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -39,6 +39,7 @@ import androidx.recyclerview.widget.RecyclerView;
|
|||
|
||||
import com.bumptech.glide.Glide;
|
||||
import com.keylesspalace.tusky.R;
|
||||
import com.keylesspalace.tusky.databinding.ItemFollowRequestBinding;
|
||||
import com.keylesspalace.tusky.entity.Account;
|
||||
import com.keylesspalace.tusky.entity.Emoji;
|
||||
import com.keylesspalace.tusky.entity.Notification;
|
||||
|
@ -125,9 +126,8 @@ public class NotificationsAdapter extends RecyclerView.Adapter {
|
|||
return new FollowViewHolder(view, statusDisplayOptions);
|
||||
}
|
||||
case VIEW_TYPE_FOLLOW_REQUEST: {
|
||||
View view = inflater
|
||||
.inflate(R.layout.item_follow_request_notification, parent, false);
|
||||
return new FollowRequestViewHolder(view, true);
|
||||
ItemFollowRequestBinding binding = ItemFollowRequestBinding.inflate(inflater, parent, false);
|
||||
return new FollowRequestViewHolder(binding, true);
|
||||
}
|
||||
case VIEW_TYPE_PLACEHOLDER: {
|
||||
View view = inflater
|
||||
|
@ -233,7 +233,7 @@ public class NotificationsAdapter extends RecyclerView.Adapter {
|
|||
if (payloadForHolder == null) {
|
||||
FollowRequestViewHolder holder = (FollowRequestViewHolder) viewHolder;
|
||||
holder.setupWithAccount(concreteNotificaton.getAccount(), statusDisplayOptions.animateAvatars(), statusDisplayOptions.animateEmojis());
|
||||
holder.setupActionListener(accountActionListener);
|
||||
holder.setupActionListener(accountActionListener, concreteNotificaton.getAccount().getId());
|
||||
}
|
||||
}
|
||||
default:
|
||||
|
|
|
@ -18,19 +18,18 @@ package com.keylesspalace.tusky.adapter
|
|||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.CheckBox
|
||||
import android.widget.RadioButton
|
||||
import android.widget.TextView
|
||||
import androidx.emoji.text.EmojiCompat
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.keylesspalace.tusky.R
|
||||
import com.keylesspalace.tusky.databinding.ItemPollBinding
|
||||
import com.keylesspalace.tusky.entity.Emoji
|
||||
import com.keylesspalace.tusky.util.*
|
||||
import com.keylesspalace.tusky.util.BindingHolder
|
||||
import com.keylesspalace.tusky.util.emojify
|
||||
import com.keylesspalace.tusky.util.visible
|
||||
import com.keylesspalace.tusky.viewdata.PollOptionViewData
|
||||
import com.keylesspalace.tusky.viewdata.buildDescription
|
||||
import com.keylesspalace.tusky.viewdata.calculatePercent
|
||||
|
||||
class PollAdapter: RecyclerView.Adapter<PollViewHolder>() {
|
||||
class PollAdapter: RecyclerView.Adapter<BindingHolder<ItemPollBinding>>() {
|
||||
|
||||
private var pollOptions: List<PollOptionViewData> = emptyList()
|
||||
private var voteCount: Int = 0
|
||||
|
@ -64,39 +63,42 @@ class PollAdapter: RecyclerView.Adapter<PollViewHolder>() {
|
|||
}
|
||||
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): PollViewHolder {
|
||||
return PollViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.item_poll, parent, false))
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BindingHolder<ItemPollBinding> {
|
||||
val binding = ItemPollBinding.inflate(LayoutInflater.from(parent.context), parent, false)
|
||||
return BindingHolder(binding)
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int {
|
||||
return pollOptions.size
|
||||
}
|
||||
override fun getItemCount() = pollOptions.size
|
||||
|
||||
override fun onBindViewHolder(holder: PollViewHolder, position: Int) {
|
||||
override fun onBindViewHolder(holder: BindingHolder<ItemPollBinding>, position: Int) {
|
||||
|
||||
val option = pollOptions[position]
|
||||
|
||||
holder.resultTextView.visible(mode == RESULT)
|
||||
holder.radioButton.visible(mode == SINGLE)
|
||||
holder.checkBox.visible(mode == MULTIPLE)
|
||||
val resultTextView = holder.binding.statusPollOptionResult
|
||||
val radioButton = holder.binding.statusPollRadioButton
|
||||
val checkBox = holder.binding.statusPollCheckbox
|
||||
|
||||
resultTextView.visible(mode == RESULT)
|
||||
radioButton.visible(mode == SINGLE)
|
||||
checkBox.visible(mode == MULTIPLE)
|
||||
|
||||
when(mode) {
|
||||
RESULT -> {
|
||||
val percent = calculatePercent(option.votesCount, votersCount, voteCount)
|
||||
val emojifiedPollOptionText = buildDescription(option.title, percent, holder.resultTextView.context)
|
||||
.emojify(emojis, holder.resultTextView, animateEmojis)
|
||||
holder.resultTextView.text = EmojiCompat.get().process(emojifiedPollOptionText)
|
||||
val emojifiedPollOptionText = buildDescription(option.title, percent, resultTextView.context)
|
||||
.emojify(emojis, resultTextView, animateEmojis)
|
||||
resultTextView.text = EmojiCompat.get().process(emojifiedPollOptionText)
|
||||
|
||||
val level = percent * 100
|
||||
|
||||
holder.resultTextView.background.level = level
|
||||
holder.resultTextView.setOnClickListener(resultClickListener)
|
||||
resultTextView.background.level = level
|
||||
resultTextView.setOnClickListener(resultClickListener)
|
||||
}
|
||||
SINGLE -> {
|
||||
val emojifiedPollOptionText = option.title.emojify(emojis, holder.radioButton, animateEmojis)
|
||||
holder.radioButton.text = EmojiCompat.get().process(emojifiedPollOptionText)
|
||||
holder.radioButton.isChecked = option.selected
|
||||
holder.radioButton.setOnClickListener {
|
||||
val emojifiedPollOptionText = option.title.emojify(emojis, radioButton, animateEmojis)
|
||||
radioButton.text = EmojiCompat.get().process(emojifiedPollOptionText)
|
||||
radioButton.isChecked = option.selected
|
||||
radioButton.setOnClickListener {
|
||||
pollOptions.forEachIndexed { index, pollOption ->
|
||||
pollOption.selected = index == holder.adapterPosition
|
||||
notifyItemChanged(index)
|
||||
|
@ -104,10 +106,10 @@ class PollAdapter: RecyclerView.Adapter<PollViewHolder>() {
|
|||
}
|
||||
}
|
||||
MULTIPLE -> {
|
||||
val emojifiedPollOptionText = option.title.emojify(emojis, holder.checkBox, animateEmojis)
|
||||
holder.checkBox.text = EmojiCompat.get().process(emojifiedPollOptionText)
|
||||
holder.checkBox.isChecked = option.selected
|
||||
holder.checkBox.setOnCheckedChangeListener { _, isChecked ->
|
||||
val emojifiedPollOptionText = option.title.emojify(emojis, checkBox, animateEmojis)
|
||||
checkBox.text = EmojiCompat.get().process(emojifiedPollOptionText)
|
||||
checkBox.isChecked = option.selected
|
||||
checkBox.setOnCheckedChangeListener { _, isChecked ->
|
||||
pollOptions[holder.adapterPosition].selected = isChecked
|
||||
}
|
||||
}
|
||||
|
@ -121,13 +123,3 @@ class PollAdapter: RecyclerView.Adapter<PollViewHolder>() {
|
|||
const val MULTIPLE = 2
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
class PollViewHolder(view: View): RecyclerView.ViewHolder(view) {
|
||||
|
||||
val resultTextView: TextView = view.findViewById(R.id.status_poll_option_result)
|
||||
val radioButton: RadioButton = view.findViewById(R.id.status_poll_radio_button)
|
||||
val checkBox: CheckBox = view.findViewById(R.id.status_poll_checkbox)
|
||||
|
||||
}
|
||||
|
|
|
@ -63,5 +63,4 @@ class PreviewPollOptionsAdapter: RecyclerView.Adapter<PreviewViewHolder>() {
|
|||
|
||||
}
|
||||
|
||||
|
||||
class PreviewViewHolder(itemView: View): RecyclerView.ViewHolder(itemView)
|
|
@ -18,19 +18,21 @@ package com.keylesspalace.tusky.adapter
|
|||
import android.content.res.ColorStateList
|
||||
import android.view.LayoutInflater
|
||||
import android.view.MotionEvent
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.core.view.size
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.viewbinding.ViewBinding
|
||||
import com.google.android.material.chip.Chip
|
||||
import com.keylesspalace.tusky.HASHTAG
|
||||
import com.keylesspalace.tusky.LIST
|
||||
import com.keylesspalace.tusky.R
|
||||
import com.keylesspalace.tusky.TabData
|
||||
import com.keylesspalace.tusky.databinding.ItemTabPreferenceBinding
|
||||
import com.keylesspalace.tusky.databinding.ItemTabPreferenceSmallBinding
|
||||
import com.keylesspalace.tusky.util.BindingHolder
|
||||
import com.keylesspalace.tusky.util.ThemeUtils
|
||||
import com.keylesspalace.tusky.util.hide
|
||||
import com.keylesspalace.tusky.util.show
|
||||
import kotlinx.android.synthetic.main.item_tab_preference.view.*
|
||||
|
||||
interface ItemInteractionListener {
|
||||
fun onTabAdded(tab: TabData)
|
||||
|
@ -44,61 +46,69 @@ interface ItemInteractionListener {
|
|||
class TabAdapter(private var data: List<TabData>,
|
||||
private val small: Boolean,
|
||||
private val listener: ItemInteractionListener,
|
||||
private var removeButtonEnabled: Boolean = false) : RecyclerView.Adapter<TabAdapter.ViewHolder>() {
|
||||
private var removeButtonEnabled: Boolean = false
|
||||
) : RecyclerView.Adapter<BindingHolder<ViewBinding>>() {
|
||||
|
||||
fun updateData(newData: List<TabData>) {
|
||||
this.data = newData
|
||||
notifyDataSetChanged()
|
||||
}
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
||||
val layoutId = if (small) {
|
||||
R.layout.item_tab_preference_small
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BindingHolder<ViewBinding> {
|
||||
val binding = if (small) {
|
||||
ItemTabPreferenceSmallBinding.inflate(LayoutInflater.from(parent.context), parent, false)
|
||||
} else {
|
||||
R.layout.item_tab_preference
|
||||
ItemTabPreferenceBinding.inflate(LayoutInflater.from(parent.context), parent, false)
|
||||
}
|
||||
val view = LayoutInflater.from(parent.context).inflate(layoutId, parent, false)
|
||||
return ViewHolder(view)
|
||||
return BindingHolder(binding)
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
||||
override fun onBindViewHolder(holder: BindingHolder<ViewBinding>, position: Int) {
|
||||
val context = holder.itemView.context
|
||||
val tab = data[position]
|
||||
if (!small && tab.id == LIST) {
|
||||
holder.itemView.textView.text = tab.arguments.getOrNull(1).orEmpty()
|
||||
} else {
|
||||
holder.itemView.textView.setText(tab.text)
|
||||
}
|
||||
holder.itemView.textView.setCompoundDrawablesRelativeWithIntrinsicBounds(tab.icon, 0, 0, 0)
|
||||
|
||||
if (small) {
|
||||
holder.itemView.textView.setOnClickListener {
|
||||
val binding = holder.binding as ItemTabPreferenceSmallBinding
|
||||
|
||||
binding.textView.setText(tab.text)
|
||||
|
||||
binding.textView.setCompoundDrawablesRelativeWithIntrinsicBounds(tab.icon, 0, 0, 0)
|
||||
|
||||
binding.textView.setOnClickListener {
|
||||
listener.onTabAdded(tab)
|
||||
}
|
||||
}
|
||||
holder.itemView.imageView?.setOnTouchListener { _, event ->
|
||||
if (event.action == MotionEvent.ACTION_DOWN) {
|
||||
listener.onStartDrag(holder)
|
||||
true
|
||||
|
||||
} else {
|
||||
val binding = holder.binding as ItemTabPreferenceBinding
|
||||
|
||||
if (tab.id == LIST) {
|
||||
binding.textView.text = tab.arguments.getOrNull(1).orEmpty()
|
||||
} else {
|
||||
false
|
||||
binding.textView.setText(tab.text)
|
||||
}
|
||||
}
|
||||
holder.itemView.removeButton?.setOnClickListener {
|
||||
listener.onTabRemoved(holder.adapterPosition)
|
||||
}
|
||||
if (holder.itemView.removeButton != null) {
|
||||
holder.itemView.removeButton.isEnabled = removeButtonEnabled
|
||||
|
||||
binding.textView.setCompoundDrawablesRelativeWithIntrinsicBounds(tab.icon, 0, 0, 0)
|
||||
|
||||
binding.imageView.setOnTouchListener { _, event ->
|
||||
if (event.action == MotionEvent.ACTION_DOWN) {
|
||||
listener.onStartDrag(holder)
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
binding.removeButton.setOnClickListener {
|
||||
listener.onTabRemoved(holder.adapterPosition)
|
||||
}
|
||||
binding.removeButton.isEnabled = removeButtonEnabled
|
||||
ThemeUtils.setDrawableTint(
|
||||
holder.itemView.context,
|
||||
holder.itemView.removeButton.drawable,
|
||||
binding.removeButton.drawable,
|
||||
(if (removeButtonEnabled) android.R.attr.textColorTertiary else R.attr.textColorDisabled)
|
||||
)
|
||||
}
|
||||
|
||||
if (!small) {
|
||||
|
||||
if (tab.id == HASHTAG) {
|
||||
holder.itemView.chipGroup.show()
|
||||
binding.chipGroup.show()
|
||||
|
||||
/*
|
||||
* The chip group will always contain the actionChip (it is defined in the xml layout).
|
||||
|
@ -107,9 +117,9 @@ class TabAdapter(private var data: List<TabData>,
|
|||
*/
|
||||
tab.arguments.forEachIndexed { i, arg ->
|
||||
|
||||
val chip = holder.itemView.chipGroup.getChildAt(i).takeUnless { it.id == R.id.actionChip } as Chip?
|
||||
val chip = binding.chipGroup.getChildAt(i).takeUnless { it.id == R.id.actionChip } as Chip?
|
||||
?: Chip(context).apply {
|
||||
holder.itemView.chipGroup.addView(this, holder.itemView.chipGroup.size - 1)
|
||||
binding.chipGroup.addView(this, binding.chipGroup.size - 1)
|
||||
chipIconTint = ColorStateList.valueOf(ThemeUtils.getColor(context, android.R.attr.textColorPrimary))
|
||||
}
|
||||
|
||||
|
@ -126,16 +136,16 @@ class TabAdapter(private var data: List<TabData>,
|
|||
}
|
||||
}
|
||||
|
||||
while(holder.itemView.chipGroup.size - 1 > tab.arguments.size) {
|
||||
holder.itemView.chipGroup.removeViewAt(tab.arguments.size)
|
||||
while(binding.chipGroup.size - 1 > tab.arguments.size) {
|
||||
binding.chipGroup.removeViewAt(tab.arguments.size)
|
||||
}
|
||||
|
||||
holder.itemView.actionChip.setOnClickListener {
|
||||
binding.actionChip.setOnClickListener {
|
||||
listener.onActionChipClicked(tab, holder.adapterPosition)
|
||||
}
|
||||
|
||||
} else {
|
||||
holder.itemView.chipGroup.hide()
|
||||
binding.chipGroup.hide()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -148,6 +158,4 @@ class TabAdapter(private var data: List<TabData>,
|
|||
notifyDataSetChanged()
|
||||
}
|
||||
}
|
||||
|
||||
class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView)
|
||||
}
|
||||
|
|
|
@ -19,19 +19,17 @@ import android.view.ContextThemeWrapper
|
|||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.TextView
|
||||
import androidx.core.view.size
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.google.android.material.chip.Chip
|
||||
import com.google.android.material.chip.ChipGroup
|
||||
import com.keylesspalace.tusky.R
|
||||
import com.keylesspalace.tusky.databinding.ItemAnnouncementBinding
|
||||
import com.keylesspalace.tusky.entity.Announcement
|
||||
import com.keylesspalace.tusky.entity.Emoji
|
||||
import com.keylesspalace.tusky.interfaces.LinkListener
|
||||
import com.keylesspalace.tusky.util.BindingHolder
|
||||
import com.keylesspalace.tusky.util.LinkHelper
|
||||
import com.keylesspalace.tusky.util.emojify
|
||||
import kotlinx.android.synthetic.main.item_announcement.view.*
|
||||
|
||||
|
||||
interface AnnouncementActionListener: LinkListener {
|
||||
fun openReactionPicker(announcementId: String, target: View)
|
||||
|
@ -44,16 +42,74 @@ class AnnouncementAdapter(
|
|||
private val listener: AnnouncementActionListener,
|
||||
private val wellbeingEnabled: Boolean = false,
|
||||
private val animateEmojis: Boolean = false
|
||||
) : RecyclerView.Adapter<AnnouncementAdapter.AnnouncementViewHolder>() {
|
||||
) : RecyclerView.Adapter<BindingHolder<ItemAnnouncementBinding>>() {
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): AnnouncementViewHolder {
|
||||
val view = LayoutInflater.from(parent.context)
|
||||
.inflate(R.layout.item_announcement, parent, false)
|
||||
return AnnouncementViewHolder(view)
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BindingHolder<ItemAnnouncementBinding> {
|
||||
val binding = ItemAnnouncementBinding.inflate(LayoutInflater.from(parent.context), parent, false)
|
||||
return BindingHolder(binding)
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(viewHolder: AnnouncementViewHolder, position: Int) {
|
||||
viewHolder.bind(items[position])
|
||||
override fun onBindViewHolder(holder: BindingHolder<ItemAnnouncementBinding>, position: Int) {
|
||||
val item = items[position]
|
||||
|
||||
val text = holder.binding.text
|
||||
val chips = holder.binding.chipGroup
|
||||
val addReactionChip = holder.binding.addReactionChip
|
||||
|
||||
LinkHelper.setClickableText(text, item.content, null, listener)
|
||||
|
||||
// If wellbeing mode is enabled, announcement badge counts should not be shown.
|
||||
if (wellbeingEnabled) {
|
||||
// Since reactions are not visible in wellbeing mode,
|
||||
// we shouldn't be able to add any ourselves.
|
||||
addReactionChip.visibility = View.GONE
|
||||
return
|
||||
}
|
||||
|
||||
item.reactions.forEachIndexed { i, reaction ->
|
||||
(chips.getChildAt(i)?.takeUnless { it.id == R.id.addReactionChip } as Chip?
|
||||
?: Chip(ContextThemeWrapper(chips.context, R.style.Widget_MaterialComponents_Chip_Choice)).apply {
|
||||
isCheckable = true
|
||||
checkedIcon = null
|
||||
chips.addView(this, i)
|
||||
})
|
||||
.apply {
|
||||
val emojiText = if (reaction.url == null) {
|
||||
reaction.name
|
||||
} else {
|
||||
context.getString(R.string.emoji_shortcode_format, reaction.name)
|
||||
}
|
||||
this.text = ("$emojiText ${reaction.count}")
|
||||
.emojify(
|
||||
listOf(Emoji(
|
||||
reaction.name,
|
||||
reaction.url ?: "",
|
||||
reaction.staticUrl ?: "",
|
||||
null
|
||||
)),
|
||||
this,
|
||||
animateEmojis
|
||||
)
|
||||
|
||||
isChecked = reaction.me
|
||||
|
||||
setOnClickListener {
|
||||
if (reaction.me) {
|
||||
listener.removeReaction(item.id, reaction.name)
|
||||
} else {
|
||||
listener.addReaction(item.id, reaction.name)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
while (chips.size - 1 > item.reactions.size) {
|
||||
chips.removeViewAt(item.reactions.size)
|
||||
}
|
||||
|
||||
addReactionChip.setOnClickListener {
|
||||
listener.openReactionPicker(item.id, it)
|
||||
}
|
||||
}
|
||||
|
||||
override fun getItemCount() = items.size
|
||||
|
@ -62,67 +118,4 @@ class AnnouncementAdapter(
|
|||
this.items = items
|
||||
notifyDataSetChanged()
|
||||
}
|
||||
|
||||
inner class AnnouncementViewHolder(private val view: View) : RecyclerView.ViewHolder(view) {
|
||||
private val text: TextView = view.text
|
||||
private val chips: ChipGroup = view.chipGroup
|
||||
private val addReactionChip: Chip = view.addReactionChip
|
||||
|
||||
fun bind(item: Announcement) {
|
||||
LinkHelper.setClickableText(text, item.content, null, listener)
|
||||
|
||||
// If wellbeing mode is enabled, announcement badge counts should not be shown.
|
||||
if (wellbeingEnabled) {
|
||||
// Since reactions are not visible in wellbeing mode,
|
||||
// we shouldn't be able to add any ourselves.
|
||||
addReactionChip.visibility = View.GONE
|
||||
return
|
||||
}
|
||||
|
||||
item.reactions.forEachIndexed { i, reaction ->
|
||||
(chips.getChildAt(i)?.takeUnless { it.id == R.id.addReactionChip } as Chip?
|
||||
?: Chip(ContextThemeWrapper(view.context, R.style.Widget_MaterialComponents_Chip_Choice)).apply {
|
||||
isCheckable = true
|
||||
checkedIcon = null
|
||||
chips.addView(this, i)
|
||||
})
|
||||
.apply {
|
||||
val emojiText = if (reaction.url == null) {
|
||||
reaction.name
|
||||
} else {
|
||||
view.context.getString(R.string.emoji_shortcode_format, reaction.name)
|
||||
}
|
||||
text = ("$emojiText ${reaction.count}")
|
||||
.emojify(
|
||||
listOf(Emoji(
|
||||
reaction.name,
|
||||
reaction.url ?: "",
|
||||
reaction.staticUrl ?: "",
|
||||
null
|
||||
)),
|
||||
this,
|
||||
animateEmojis
|
||||
)
|
||||
|
||||
isChecked = reaction.me
|
||||
|
||||
setOnClickListener {
|
||||
if (reaction.me) {
|
||||
listener.removeReaction(item.id, reaction.name)
|
||||
} else {
|
||||
listener.addReaction(item.id, reaction.name)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
while (chips.size - 1 > item.reactions.size) {
|
||||
chips.removeViewAt(item.reactions.size)
|
||||
}
|
||||
|
||||
addReactionChip.setOnClickListener {
|
||||
listener.openReactionPicker(item.id, it)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,7 +22,6 @@ import android.view.LayoutInflater
|
|||
import android.view.WindowManager
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import com.keylesspalace.tusky.R
|
||||
import com.keylesspalace.tusky.adapter.AddPollOptionsAdapter
|
||||
import com.keylesspalace.tusky.databinding.DialogAddPollBinding
|
||||
import com.keylesspalace.tusky.entity.NewPoll
|
||||
|
||||
|
|
|
@ -13,17 +13,16 @@
|
|||
* 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
|
||||
package com.keylesspalace.tusky.components.compose.dialog
|
||||
|
||||
import android.text.InputFilter
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.ImageButton
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.google.android.material.textfield.TextInputEditText
|
||||
import com.google.android.material.textfield.TextInputLayout
|
||||
import com.keylesspalace.tusky.R
|
||||
import com.keylesspalace.tusky.databinding.ItemAddPollOptionBinding
|
||||
import com.keylesspalace.tusky.util.BindingHolder
|
||||
import com.keylesspalace.tusky.util.onTextChanged
|
||||
import com.keylesspalace.tusky.util.visible
|
||||
|
||||
|
@ -32,7 +31,7 @@ class AddPollOptionsAdapter(
|
|||
private val maxOptionLength: Int,
|
||||
private val onOptionRemoved: (Boolean) -> Unit,
|
||||
private val onOptionChanged: (Boolean) -> Unit
|
||||
): RecyclerView.Adapter<ViewHolder>() {
|
||||
): RecyclerView.Adapter<BindingHolder<ItemAddPollOptionBinding>>() {
|
||||
|
||||
val pollOptions: List<String>
|
||||
get() = options.toList()
|
||||
|
@ -42,11 +41,12 @@ class AddPollOptionsAdapter(
|
|||
notifyItemInserted(options.size - 1)
|
||||
}
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
||||
val holder = ViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.item_add_poll_option, parent, false))
|
||||
holder.editText.filters = arrayOf(InputFilter.LengthFilter(maxOptionLength))
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BindingHolder<ItemAddPollOptionBinding> {
|
||||
val binding = ItemAddPollOptionBinding.inflate(LayoutInflater.from(parent.context), parent, false)
|
||||
val holder = BindingHolder(binding)
|
||||
binding.optionEditText.filters = arrayOf(InputFilter.LengthFilter(maxOptionLength))
|
||||
|
||||
holder.editText.onTextChanged { s, _, _, _ ->
|
||||
binding.optionEditText.onTextChanged { s, _, _, _ ->
|
||||
val pos = holder.adapterPosition
|
||||
if(pos != RecyclerView.NO_POSITION) {
|
||||
options[pos] = s.toString()
|
||||
|
@ -59,15 +59,15 @@ class AddPollOptionsAdapter(
|
|||
|
||||
override fun getItemCount() = options.size
|
||||
|
||||
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
||||
holder.editText.setText(options[position])
|
||||
override fun onBindViewHolder(holder: BindingHolder<ItemAddPollOptionBinding>, position: Int) {
|
||||
holder.binding.optionEditText.setText(options[position])
|
||||
|
||||
holder.textInputLayout.hint = holder.textInputLayout.context.getString(R.string.poll_new_choice_hint, position + 1)
|
||||
holder.binding.optionTextInputLayout.hint = holder.binding.root.context.getString(R.string.poll_new_choice_hint, position + 1)
|
||||
|
||||
holder.deleteButton.visible(position > 1, View.INVISIBLE)
|
||||
holder.binding.deleteButton.visible(position > 1, View.INVISIBLE)
|
||||
|
||||
holder.deleteButton.setOnClickListener {
|
||||
holder.editText.clearFocus()
|
||||
holder.binding.deleteButton.setOnClickListener {
|
||||
holder.binding.optionEditText.clearFocus()
|
||||
options.removeAt(holder.adapterPosition)
|
||||
notifyItemRemoved(holder.adapterPosition)
|
||||
onOptionRemoved(validateInput())
|
||||
|
@ -81,12 +81,4 @@ class AddPollOptionsAdapter(
|
|||
|
||||
return true
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
class ViewHolder(itemView: View): RecyclerView.ViewHolder(itemView) {
|
||||
val textInputLayout: TextInputLayout = itemView.findViewById(R.id.optionTextInputLayout)
|
||||
val editText: TextInputEditText = itemView.findViewById(R.id.optionEditText)
|
||||
val deleteButton: ImageButton = itemView.findViewById(R.id.deleteButton)
|
||||
}
|
|
@ -1,3 +1,18 @@
|
|||
/* Copyright 2021 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.conversation
|
||||
|
||||
import android.view.LayoutInflater
|
||||
|
@ -10,6 +25,7 @@ import androidx.recyclerview.widget.ListUpdateCallback
|
|||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.keylesspalace.tusky.R
|
||||
import com.keylesspalace.tusky.adapter.NetworkStateViewHolder
|
||||
import com.keylesspalace.tusky.databinding.ItemNetworkStateBinding
|
||||
import com.keylesspalace.tusky.interfaces.StatusActionListener
|
||||
import com.keylesspalace.tusky.util.NetworkState
|
||||
import com.keylesspalace.tusky.util.StatusDisplayOptions
|
||||
|
@ -49,11 +65,15 @@ class ConversationAdapter(
|
|||
}
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
|
||||
val view = LayoutInflater.from(parent.context).inflate(viewType, parent, false)
|
||||
return when (viewType) {
|
||||
R.layout.item_network_state -> NetworkStateViewHolder(view, retryCallback)
|
||||
R.layout.item_conversation -> ConversationViewHolder(view, statusDisplayOptions,
|
||||
listener)
|
||||
R.layout.item_network_state -> {
|
||||
val binding = ItemNetworkStateBinding.inflate(LayoutInflater.from(parent.context), parent, false)
|
||||
NetworkStateViewHolder(binding, retryCallback)
|
||||
}
|
||||
R.layout.item_conversation -> {
|
||||
val view = LayoutInflater.from(parent.context).inflate(viewType, parent, false)
|
||||
ConversationViewHolder(view, statusDisplayOptions, listener)
|
||||
}
|
||||
else -> throw IllegalArgumentException("unknown view type $viewType")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,7 +23,7 @@ import androidx.recyclerview.widget.LinearLayoutManager
|
|||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.keylesspalace.tusky.databinding.ItemDraftBinding
|
||||
import com.keylesspalace.tusky.db.DraftEntity
|
||||
import com.keylesspalace.tusky.util.BindingViewHolder
|
||||
import com.keylesspalace.tusky.util.BindingHolder
|
||||
import com.keylesspalace.tusky.util.hide
|
||||
import com.keylesspalace.tusky.util.show
|
||||
import com.keylesspalace.tusky.util.visible
|
||||
|
@ -35,7 +35,7 @@ interface DraftActionListener {
|
|||
|
||||
class DraftsAdapter(
|
||||
private val listener: DraftActionListener
|
||||
) : PagedListAdapter<DraftEntity, BindingViewHolder<ItemDraftBinding>>(
|
||||
) : PagedListAdapter<DraftEntity, BindingHolder<ItemDraftBinding>>(
|
||||
object : DiffUtil.ItemCallback<DraftEntity>() {
|
||||
override fun areItemsTheSame(oldItem: DraftEntity, newItem: DraftEntity): Boolean {
|
||||
return oldItem.id == newItem.id
|
||||
|
@ -47,11 +47,11 @@ class DraftsAdapter(
|
|||
}
|
||||
) {
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BindingViewHolder<ItemDraftBinding> {
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BindingHolder<ItemDraftBinding> {
|
||||
|
||||
val binding = ItemDraftBinding.inflate(LayoutInflater.from(parent.context), parent, false)
|
||||
|
||||
val viewHolder = BindingViewHolder(binding)
|
||||
val viewHolder = BindingHolder(binding)
|
||||
|
||||
binding.draftMediaPreview.layoutManager = LinearLayoutManager(binding.root.context, RecyclerView.HORIZONTAL, false)
|
||||
binding.draftMediaPreview.adapter = DraftMediaAdapter {
|
||||
|
@ -63,7 +63,7 @@ class DraftsAdapter(
|
|||
return viewHolder
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: BindingViewHolder<ItemDraftBinding>, position: Int) {
|
||||
override fun onBindViewHolder(holder: BindingHolder<ItemDraftBinding>, position: Int) {
|
||||
getItem(position)?.let { draft ->
|
||||
holder.binding.root.setOnClickListener {
|
||||
listener.onOpenDraft(draft)
|
||||
|
|
|
@ -1,22 +1,31 @@
|
|||
package com.keylesspalace.tusky.components.instancemute.adapter
|
||||
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.keylesspalace.tusky.R
|
||||
import com.keylesspalace.tusky.components.instancemute.interfaces.InstanceActionListener
|
||||
import kotlinx.android.synthetic.main.item_muted_domain.view.*
|
||||
import com.keylesspalace.tusky.databinding.ItemMutedDomainBinding
|
||||
import com.keylesspalace.tusky.util.BindingHolder
|
||||
|
||||
class DomainMutesAdapter(
|
||||
private val actionListener: InstanceActionListener
|
||||
): RecyclerView.Adapter<BindingHolder<ItemMutedDomainBinding>>() {
|
||||
|
||||
class DomainMutesAdapter(private val actionListener: InstanceActionListener): RecyclerView.Adapter<DomainMutesAdapter.ViewHolder>() {
|
||||
var instances: MutableList<String> = mutableListOf()
|
||||
var bottomLoading: Boolean = false
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
||||
return ViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.item_muted_domain, parent, false), actionListener)
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BindingHolder<ItemMutedDomainBinding> {
|
||||
val binding = ItemMutedDomainBinding.inflate(LayoutInflater.from(parent.context), parent, false)
|
||||
return BindingHolder(binding)
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
||||
holder.setupWithInstance(instances[position])
|
||||
override fun onBindViewHolder(holder: BindingHolder<ItemMutedDomainBinding>, position: Int) {
|
||||
val instance = instances[position]
|
||||
|
||||
holder.binding.mutedDomain.text = instance
|
||||
holder.binding.mutedDomainUnmute.setOnClickListener {
|
||||
actionListener.mute(false, instance, holder.adapterPosition)
|
||||
}
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int {
|
||||
|
@ -37,21 +46,10 @@ class DomainMutesAdapter(private val actionListener: InstanceActionListener): Re
|
|||
notifyItemInserted(instances.size)
|
||||
}
|
||||
|
||||
fun removeItem(position: Int)
|
||||
{
|
||||
fun removeItem(position: Int) {
|
||||
if (position >= 0 && position < instances.size) {
|
||||
instances.removeAt(position)
|
||||
notifyItemRemoved(position)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class ViewHolder(rootView: View, private val actionListener: InstanceActionListener): RecyclerView.ViewHolder(rootView) {
|
||||
fun setupWithInstance(instance: String) {
|
||||
itemView.muted_domain.text = instance
|
||||
itemView.muted_domain_unmute.setOnClickListener {
|
||||
actionListener.mute(false, instance, adapterPosition)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -18,13 +18,11 @@ package com.keylesspalace.tusky.components.scheduled
|
|||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.ImageButton
|
||||
import android.widget.TextView
|
||||
import androidx.paging.PagedListAdapter
|
||||
import androidx.recyclerview.widget.DiffUtil
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.keylesspalace.tusky.R
|
||||
import com.keylesspalace.tusky.databinding.ItemScheduledTootBinding
|
||||
import com.keylesspalace.tusky.entity.ScheduledStatus
|
||||
import com.keylesspalace.tusky.util.BindingHolder
|
||||
|
||||
interface ScheduledTootActionListener {
|
||||
fun edit(item: ScheduledStatus)
|
||||
|
@ -33,7 +31,7 @@ interface ScheduledTootActionListener {
|
|||
|
||||
class ScheduledTootAdapter(
|
||||
val listener: ScheduledTootActionListener
|
||||
) : PagedListAdapter<ScheduledStatus, ScheduledTootAdapter.TootViewHolder>(
|
||||
) : PagedListAdapter<ScheduledStatus, BindingHolder<ItemScheduledTootBinding>>(
|
||||
object: DiffUtil.ItemCallback<ScheduledStatus>(){
|
||||
override fun areItemsTheSame(oldItem: ScheduledStatus, newItem: ScheduledStatus): Boolean {
|
||||
return oldItem.id == newItem.id
|
||||
|
@ -46,40 +44,24 @@ class ScheduledTootAdapter(
|
|||
}
|
||||
) {
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TootViewHolder {
|
||||
val view = LayoutInflater.from(parent.context)
|
||||
.inflate(R.layout.item_scheduled_toot, parent, false)
|
||||
return TootViewHolder(view)
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BindingHolder<ItemScheduledTootBinding> {
|
||||
val binding = ItemScheduledTootBinding.inflate(LayoutInflater.from(parent.context), parent, false)
|
||||
return BindingHolder(binding)
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(viewHolder: TootViewHolder, position: Int) {
|
||||
getItem(position)?.let{
|
||||
viewHolder.bind(it)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
inner class TootViewHolder(view: View) : RecyclerView.ViewHolder(view) {
|
||||
|
||||
private val text: TextView = view.findViewById(R.id.text)
|
||||
private val edit: ImageButton = view.findViewById(R.id.edit)
|
||||
private val delete: ImageButton = view.findViewById(R.id.delete)
|
||||
|
||||
fun bind(item: ScheduledStatus) {
|
||||
edit.isEnabled = true
|
||||
delete.isEnabled = true
|
||||
text.text = item.params.text
|
||||
edit.setOnClickListener { v: View ->
|
||||
override fun onBindViewHolder(holder: BindingHolder<ItemScheduledTootBinding>, position: Int) {
|
||||
getItem(position)?.let{ item ->
|
||||
holder.binding.edit.isEnabled = true
|
||||
holder.binding.delete.isEnabled = true
|
||||
holder.binding.text.text = item.params.text
|
||||
holder.binding.edit.setOnClickListener { v: View ->
|
||||
v.isEnabled = false
|
||||
listener.edit(item)
|
||||
}
|
||||
delete.setOnClickListener { v: View ->
|
||||
holder.binding.delete.setOnClickListener { v: View ->
|
||||
v.isEnabled = false
|
||||
listener.delete(item)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -19,24 +19,23 @@ import android.view.LayoutInflater
|
|||
import android.view.ViewGroup
|
||||
import androidx.paging.PagedListAdapter
|
||||
import androidx.recyclerview.widget.DiffUtil
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.keylesspalace.tusky.R
|
||||
import com.keylesspalace.tusky.adapter.HashtagViewHolder
|
||||
import com.keylesspalace.tusky.databinding.ItemHashtagBinding
|
||||
import com.keylesspalace.tusky.entity.HashTag
|
||||
import com.keylesspalace.tusky.interfaces.LinkListener
|
||||
import com.keylesspalace.tusky.util.BindingHolder
|
||||
|
||||
class SearchHashtagsAdapter(private val linkListener: LinkListener)
|
||||
: PagedListAdapter<HashTag, RecyclerView.ViewHolder>(HASHTAG_COMPARATOR) {
|
||||
: PagedListAdapter<HashTag, BindingHolder<ItemHashtagBinding>>(HASHTAG_COMPARATOR) {
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
|
||||
val view = LayoutInflater.from(parent.context)
|
||||
.inflate(R.layout.item_hashtag, parent, false)
|
||||
return HashtagViewHolder(view)
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BindingHolder<ItemHashtagBinding> {
|
||||
val binding = ItemHashtagBinding.inflate(LayoutInflater.from(parent.context), parent, false)
|
||||
return BindingHolder(binding)
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
|
||||
override fun onBindViewHolder(holder: BindingHolder<ItemHashtagBinding>, position: Int) {
|
||||
getItem(position)?.let { (name) ->
|
||||
(holder as HashtagViewHolder).setup(name, linkListener)
|
||||
holder.binding.root.text = String.format("#%s", name)
|
||||
holder.binding.root.setOnClickListener { linkListener.onViewTag(name) }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -3,6 +3,6 @@ package com.keylesspalace.tusky.util
|
|||
import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.viewbinding.ViewBinding
|
||||
|
||||
class BindingViewHolder<T : ViewBinding>(
|
||||
class BindingHolder<T : ViewBinding>(
|
||||
val binding: T
|
||||
) : RecyclerView.ViewHolder(binding.root)
|
|
@ -1,52 +1,69 @@
|
|||
<?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:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="72dp"
|
||||
android:gravity="center_vertical"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingLeft="16dp"
|
||||
android:paddingRight="16dp">
|
||||
android:paddingRight="16dp"
|
||||
android:paddingBottom="10dp">
|
||||
|
||||
<androidx.emoji.widget.EmojiTextView
|
||||
android:id="@+id/notificationTextView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:drawableStart="@drawable/ic_person_add_24dp"
|
||||
android:drawablePadding="10dp"
|
||||
android:ellipsize="end"
|
||||
android:gravity="center_vertical"
|
||||
android:maxLines="1"
|
||||
android:paddingStart="28dp"
|
||||
android:textColor="?android:textColorSecondary"
|
||||
android:textSize="?attr/status_text_medium"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:text="Someone requested to follow you" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/avatar"
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="48dp"
|
||||
android:layout_alignParentStart="true"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_marginEnd="24dp"
|
||||
android:contentDescription="@string/action_view_profile" />
|
||||
android:layout_marginTop="10dp"
|
||||
android:contentDescription="@string/action_view_profile"
|
||||
tools:src="@drawable/avatar_default"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/notificationTextView" />
|
||||
|
||||
<LinearLayout
|
||||
<androidx.emoji.widget.EmojiTextView
|
||||
android:id="@+id/displayNameTextView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_toEndOf="@id/avatar"
|
||||
android:layout_toStartOf="@id/acceptButton"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="vertical">
|
||||
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_constraintStart_toEndOf="@id/avatar"
|
||||
app:layout_constraintTop_toTopOf="@id/avatar"
|
||||
app:layout_constraintBottom_toTopOf="@id/usernameTextView"
|
||||
tools:text="Display name" />
|
||||
|
||||
<androidx.emoji.widget.EmojiTextView
|
||||
android:id="@+id/displayNameTextView"
|
||||
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/usernameTextView"
|
||||
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>
|
||||
<TextView
|
||||
android:id="@+id/usernameTextView"
|
||||
android:layout_width="wrap_content"
|
||||
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_constraintStart_toEndOf="@id/avatar"
|
||||
app:layout_constraintTop_toBottomOf="@id/displayNameTextView"
|
||||
app:layout_constraintBottom_toBottomOf="@id/avatar"
|
||||
tools:text="\@username" />
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/acceptButton"
|
||||
|
@ -55,10 +72,12 @@
|
|||
android:layout_height="32dp"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_marginStart="12dp"
|
||||
android:layout_toStartOf="@id/rejectButton"
|
||||
android:layout_marginTop="14dp"
|
||||
android:background="?attr/selectableItemBackgroundBorderless"
|
||||
android:contentDescription="@string/action_accept"
|
||||
android:padding="4dp"
|
||||
app:layout_constraintEnd_toStartOf="@id/rejectButton"
|
||||
app:layout_constraintTop_toBottomOf="@id/notificationTextView"
|
||||
app:srcCompat="@drawable/ic_check_24dp" />
|
||||
|
||||
<ImageButton
|
||||
|
@ -66,12 +85,14 @@
|
|||
style="@style/TuskyImageButton"
|
||||
android:layout_width="32dp"
|
||||
android:layout_height="32dp"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_marginStart="12dp"
|
||||
android:layout_marginTop="14dp"
|
||||
android:background="?attr/selectableItemBackgroundBorderless"
|
||||
android:contentDescription="@string/action_reject"
|
||||
android:padding="4dp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/notificationTextView"
|
||||
app:srcCompat="@drawable/ic_reject_24dp" />
|
||||
|
||||
</RelativeLayout>
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
|
|
@ -1,96 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center_vertical"
|
||||
android:paddingLeft="16dp"
|
||||
android:paddingRight="16dp"
|
||||
android:paddingBottom="10dp">
|
||||
|
||||
<androidx.emoji.widget.EmojiTextView
|
||||
android:id="@+id/notificationTextView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:drawableStart="@drawable/ic_person_add_24dp"
|
||||
android:drawablePadding="10dp"
|
||||
android:ellipsize="end"
|
||||
android:gravity="center_vertical"
|
||||
android:maxLines="1"
|
||||
android:paddingStart="28dp"
|
||||
android:textColor="?android:textColorSecondary"
|
||||
android:textSize="?attr/status_text_medium"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:text="Someone requested to follow you" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/avatar"
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="48dp"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_marginTop="10dp"
|
||||
android:contentDescription="@string/action_view_profile"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/notificationTextView" />
|
||||
|
||||
<androidx.emoji.widget.EmojiTextView
|
||||
android:id="@+id/displayNameTextView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="14dp"
|
||||
android:layout_marginTop="6dp"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
android:textColor="?android:textColorPrimary"
|
||||
android:textSize="?attr/status_text_large"
|
||||
android:textStyle="normal|bold"
|
||||
app:layout_constraintStart_toEndOf="@id/avatar"
|
||||
app:layout_constraintTop_toBottomOf="@id/notificationTextView"
|
||||
tools:text="Display name" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/usernameTextView"
|
||||
android:layout_width="wrap_content"
|
||||
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_constraintStart_toEndOf="@id/avatar"
|
||||
app:layout_constraintTop_toBottomOf="@id/displayNameTextView"
|
||||
tools:text="\@username" />
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/acceptButton"
|
||||
style="@style/TuskyImageButton"
|
||||
android:layout_width="32dp"
|
||||
android:layout_height="32dp"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_marginStart="12dp"
|
||||
android:layout_marginTop="14dp"
|
||||
android:background="?attr/selectableItemBackgroundBorderless"
|
||||
android:contentDescription="@string/action_accept"
|
||||
android:padding="4dp"
|
||||
app:layout_constraintEnd_toStartOf="@id/rejectButton"
|
||||
app:layout_constraintTop_toBottomOf="@id/notificationTextView"
|
||||
app:srcCompat="@drawable/ic_check_24dp" />
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/rejectButton"
|
||||
style="@style/TuskyImageButton"
|
||||
android:layout_width="32dp"
|
||||
android:layout_height="32dp"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_marginStart="12dp"
|
||||
android:layout_marginTop="14dp"
|
||||
android:background="?attr/selectableItemBackgroundBorderless"
|
||||
android:contentDescription="@string/action_reject"
|
||||
android:padding="4dp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/notificationTextView"
|
||||
app:srcCompat="@drawable/ic_reject_24dp" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
@ -1,6 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/hashtag"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="16dp"
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/title"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="16dp"
|
||||
|
|
Loading…
Reference in a new issue