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