Make links in bios of follow request and follow notifications work (#3646)
* make links in bios of follow request and follow notifications work * use ClickableSpanTextView to display account notes
This commit is contained in:
parent
ad9e57cb10
commit
74a00c0591
9 changed files with 47 additions and 13 deletions
|
@ -25,11 +25,14 @@ import com.keylesspalace.tusky.components.notifications.NotificationsPagingAdapt
|
||||||
import com.keylesspalace.tusky.databinding.ItemFollowRequestBinding
|
import com.keylesspalace.tusky.databinding.ItemFollowRequestBinding
|
||||||
import com.keylesspalace.tusky.entity.TimelineAccount
|
import com.keylesspalace.tusky.entity.TimelineAccount
|
||||||
import com.keylesspalace.tusky.interfaces.AccountActionListener
|
import com.keylesspalace.tusky.interfaces.AccountActionListener
|
||||||
|
import com.keylesspalace.tusky.interfaces.LinkListener
|
||||||
import com.keylesspalace.tusky.util.StatusDisplayOptions
|
import com.keylesspalace.tusky.util.StatusDisplayOptions
|
||||||
import com.keylesspalace.tusky.util.emojify
|
import com.keylesspalace.tusky.util.emojify
|
||||||
import com.keylesspalace.tusky.util.hide
|
import com.keylesspalace.tusky.util.hide
|
||||||
import com.keylesspalace.tusky.util.loadAvatar
|
import com.keylesspalace.tusky.util.loadAvatar
|
||||||
import com.keylesspalace.tusky.util.parseAsMastodonHtml
|
import com.keylesspalace.tusky.util.parseAsMastodonHtml
|
||||||
|
import com.keylesspalace.tusky.util.setClickableText
|
||||||
|
import com.keylesspalace.tusky.util.show
|
||||||
import com.keylesspalace.tusky.util.unicodeWrap
|
import com.keylesspalace.tusky.util.unicodeWrap
|
||||||
import com.keylesspalace.tusky.util.visible
|
import com.keylesspalace.tusky.util.visible
|
||||||
import com.keylesspalace.tusky.viewdata.NotificationViewData
|
import com.keylesspalace.tusky.viewdata.NotificationViewData
|
||||||
|
@ -37,6 +40,7 @@ import com.keylesspalace.tusky.viewdata.NotificationViewData
|
||||||
class FollowRequestViewHolder(
|
class FollowRequestViewHolder(
|
||||||
private val binding: ItemFollowRequestBinding,
|
private val binding: ItemFollowRequestBinding,
|
||||||
private val accountActionListener: AccountActionListener,
|
private val accountActionListener: AccountActionListener,
|
||||||
|
private val linkListener: LinkListener,
|
||||||
private val showHeader: Boolean
|
private val showHeader: Boolean
|
||||||
) : NotificationsPagingAdapter.ViewHolder, RecyclerView.ViewHolder(binding.root) {
|
) : NotificationsPagingAdapter.ViewHolder, RecyclerView.ViewHolder(binding.root) {
|
||||||
|
|
||||||
|
@ -92,9 +96,11 @@ class FollowRequestViewHolder(
|
||||||
if (account.note.isEmpty()) {
|
if (account.note.isEmpty()) {
|
||||||
binding.accountNote.hide()
|
binding.accountNote.hide()
|
||||||
} else {
|
} else {
|
||||||
binding.accountNote.text =
|
binding.accountNote.show()
|
||||||
account.note.parseAsMastodonHtml()
|
|
||||||
.emojify(account.emojis, binding.accountNote, animateEmojis)
|
val emojifiedNote = account.note.parseAsMastodonHtml()
|
||||||
|
.emojify(account.emojis, binding.accountNote, animateEmojis)
|
||||||
|
setClickableText(binding.accountNote, emojifiedNote, emptyList(), null, linkListener)
|
||||||
}
|
}
|
||||||
val avatarRadius = binding.avatar.context.resources.getDimensionPixelSize(R.dimen.avatar_radius_48dp)
|
val avatarRadius = binding.avatar.context.resources.getDimensionPixelSize(R.dimen.avatar_radius_48dp)
|
||||||
loadAvatar(account.avatar, binding.avatar, avatarRadius, animateAvatar)
|
loadAvatar(account.avatar, binding.avatar, avatarRadius, animateAvatar)
|
||||||
|
|
|
@ -19,14 +19,14 @@ import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import androidx.fragment.app.commit
|
import androidx.fragment.app.commit
|
||||||
import com.keylesspalace.tusky.BaseActivity
|
import com.keylesspalace.tusky.BottomSheetActivity
|
||||||
import com.keylesspalace.tusky.R
|
import com.keylesspalace.tusky.R
|
||||||
import com.keylesspalace.tusky.databinding.ActivityAccountListBinding
|
import com.keylesspalace.tusky.databinding.ActivityAccountListBinding
|
||||||
import dagger.android.DispatchingAndroidInjector
|
import dagger.android.DispatchingAndroidInjector
|
||||||
import dagger.android.HasAndroidInjector
|
import dagger.android.HasAndroidInjector
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class AccountListActivity : BaseActivity(), HasAndroidInjector {
|
class AccountListActivity : BottomSheetActivity(), HasAndroidInjector {
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
lateinit var dispatchingAndroidInjector: DispatchingAndroidInjector<Any>
|
lateinit var dispatchingAndroidInjector: DispatchingAndroidInjector<Any>
|
||||||
|
|
|
@ -32,7 +32,10 @@ import autodispose2.androidx.lifecycle.AndroidLifecycleScopeProvider.from
|
||||||
import autodispose2.autoDispose
|
import autodispose2.autoDispose
|
||||||
import com.google.android.material.snackbar.Snackbar
|
import com.google.android.material.snackbar.Snackbar
|
||||||
import com.keylesspalace.tusky.BaseActivity
|
import com.keylesspalace.tusky.BaseActivity
|
||||||
|
import com.keylesspalace.tusky.BottomSheetActivity
|
||||||
|
import com.keylesspalace.tusky.PostLookupFallbackBehavior
|
||||||
import com.keylesspalace.tusky.R
|
import com.keylesspalace.tusky.R
|
||||||
|
import com.keylesspalace.tusky.StatusListActivity
|
||||||
import com.keylesspalace.tusky.components.account.AccountActivity
|
import com.keylesspalace.tusky.components.account.AccountActivity
|
||||||
import com.keylesspalace.tusky.components.accountlist.AccountListActivity.Type
|
import com.keylesspalace.tusky.components.accountlist.AccountListActivity.Type
|
||||||
import com.keylesspalace.tusky.components.accountlist.adapter.AccountAdapter
|
import com.keylesspalace.tusky.components.accountlist.adapter.AccountAdapter
|
||||||
|
@ -47,6 +50,7 @@ import com.keylesspalace.tusky.di.Injectable
|
||||||
import com.keylesspalace.tusky.entity.Relationship
|
import com.keylesspalace.tusky.entity.Relationship
|
||||||
import com.keylesspalace.tusky.entity.TimelineAccount
|
import com.keylesspalace.tusky.entity.TimelineAccount
|
||||||
import com.keylesspalace.tusky.interfaces.AccountActionListener
|
import com.keylesspalace.tusky.interfaces.AccountActionListener
|
||||||
|
import com.keylesspalace.tusky.interfaces.LinkListener
|
||||||
import com.keylesspalace.tusky.network.MastodonApi
|
import com.keylesspalace.tusky.network.MastodonApi
|
||||||
import com.keylesspalace.tusky.settings.PrefKeys
|
import com.keylesspalace.tusky.settings.PrefKeys
|
||||||
import com.keylesspalace.tusky.util.HttpHeaderLink
|
import com.keylesspalace.tusky.util.HttpHeaderLink
|
||||||
|
@ -60,7 +64,11 @@ import retrofit2.Response
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class AccountListFragment : Fragment(R.layout.fragment_account_list), AccountActionListener, Injectable {
|
class AccountListFragment :
|
||||||
|
Fragment(R.layout.fragment_account_list),
|
||||||
|
AccountActionListener,
|
||||||
|
LinkListener,
|
||||||
|
Injectable {
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
lateinit var api: MastodonApi
|
lateinit var api: MastodonApi
|
||||||
|
@ -107,7 +115,7 @@ class AccountListFragment : Fragment(R.layout.fragment_account_list), AccountAct
|
||||||
instanceName = accountManager.activeAccount!!.domain,
|
instanceName = accountManager.activeAccount!!.domain,
|
||||||
accountLocked = arguments?.getBoolean(ARG_ACCOUNT_LOCKED) == true
|
accountLocked = arguments?.getBoolean(ARG_ACCOUNT_LOCKED) == true
|
||||||
)
|
)
|
||||||
val followRequestsAdapter = FollowRequestsAdapter(this, animateAvatar, animateEmojis, showBotOverlay)
|
val followRequestsAdapter = FollowRequestsAdapter(this, this, animateAvatar, animateEmojis, showBotOverlay)
|
||||||
binding.recyclerView.adapter = ConcatAdapter(headerAdapter, followRequestsAdapter)
|
binding.recyclerView.adapter = ConcatAdapter(headerAdapter, followRequestsAdapter)
|
||||||
followRequestsAdapter
|
followRequestsAdapter
|
||||||
}
|
}
|
||||||
|
@ -131,6 +139,11 @@ class AccountListFragment : Fragment(R.layout.fragment_account_list), AccountAct
|
||||||
fetchAccounts()
|
fetchAccounts()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onViewTag(tag: String) {
|
||||||
|
(activity as BaseActivity?)
|
||||||
|
?.startActivityWithSlideInAnimation(StatusListActivity.newHashtagIntent(requireContext(), tag))
|
||||||
|
}
|
||||||
|
|
||||||
override fun onViewAccount(id: String) {
|
override fun onViewAccount(id: String) {
|
||||||
(activity as BaseActivity?)?.let {
|
(activity as BaseActivity?)?.let {
|
||||||
val intent = AccountActivity.getIntent(it, id)
|
val intent = AccountActivity.getIntent(it, id)
|
||||||
|
@ -138,6 +151,10 @@ class AccountListFragment : Fragment(R.layout.fragment_account_list), AccountAct
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onViewUrl(url: String) {
|
||||||
|
(activity as BottomSheetActivity?)?.viewUrl(url, PostLookupFallbackBehavior.OPEN_IN_BROWSER)
|
||||||
|
}
|
||||||
|
|
||||||
override fun onMute(mute: Boolean, id: String, position: Int, notifications: Boolean) {
|
override fun onMute(mute: Boolean, id: String, position: Int, notifications: Boolean) {
|
||||||
viewLifecycleOwner.lifecycleScope.launch {
|
viewLifecycleOwner.lifecycleScope.launch {
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -20,10 +20,12 @@ import android.view.ViewGroup
|
||||||
import com.keylesspalace.tusky.adapter.FollowRequestViewHolder
|
import com.keylesspalace.tusky.adapter.FollowRequestViewHolder
|
||||||
import com.keylesspalace.tusky.databinding.ItemFollowRequestBinding
|
import com.keylesspalace.tusky.databinding.ItemFollowRequestBinding
|
||||||
import com.keylesspalace.tusky.interfaces.AccountActionListener
|
import com.keylesspalace.tusky.interfaces.AccountActionListener
|
||||||
|
import com.keylesspalace.tusky.interfaces.LinkListener
|
||||||
|
|
||||||
/** Displays a list of follow requests with accept/reject buttons. */
|
/** Displays a list of follow requests with accept/reject buttons. */
|
||||||
class FollowRequestsAdapter(
|
class FollowRequestsAdapter(
|
||||||
accountActionListener: AccountActionListener,
|
accountActionListener: AccountActionListener,
|
||||||
|
private val linkListener: LinkListener,
|
||||||
animateAvatar: Boolean,
|
animateAvatar: Boolean,
|
||||||
animateEmojis: Boolean,
|
animateEmojis: Boolean,
|
||||||
showBotOverlay: Boolean
|
showBotOverlay: Boolean
|
||||||
|
@ -43,6 +45,7 @@ class FollowRequestsAdapter(
|
||||||
return FollowRequestViewHolder(
|
return FollowRequestViewHolder(
|
||||||
binding,
|
binding,
|
||||||
accountActionListener,
|
accountActionListener,
|
||||||
|
linkListener,
|
||||||
showHeader = false
|
showHeader = false
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,16 +22,19 @@ import com.keylesspalace.tusky.R
|
||||||
import com.keylesspalace.tusky.databinding.ItemFollowBinding
|
import com.keylesspalace.tusky.databinding.ItemFollowBinding
|
||||||
import com.keylesspalace.tusky.entity.Notification
|
import com.keylesspalace.tusky.entity.Notification
|
||||||
import com.keylesspalace.tusky.entity.TimelineAccount
|
import com.keylesspalace.tusky.entity.TimelineAccount
|
||||||
|
import com.keylesspalace.tusky.interfaces.LinkListener
|
||||||
import com.keylesspalace.tusky.util.StatusDisplayOptions
|
import com.keylesspalace.tusky.util.StatusDisplayOptions
|
||||||
import com.keylesspalace.tusky.util.emojify
|
import com.keylesspalace.tusky.util.emojify
|
||||||
import com.keylesspalace.tusky.util.loadAvatar
|
import com.keylesspalace.tusky.util.loadAvatar
|
||||||
import com.keylesspalace.tusky.util.parseAsMastodonHtml
|
import com.keylesspalace.tusky.util.parseAsMastodonHtml
|
||||||
|
import com.keylesspalace.tusky.util.setClickableText
|
||||||
import com.keylesspalace.tusky.util.unicodeWrap
|
import com.keylesspalace.tusky.util.unicodeWrap
|
||||||
import com.keylesspalace.tusky.viewdata.NotificationViewData
|
import com.keylesspalace.tusky.viewdata.NotificationViewData
|
||||||
|
|
||||||
class FollowViewHolder(
|
class FollowViewHolder(
|
||||||
private val binding: ItemFollowBinding,
|
private val binding: ItemFollowBinding,
|
||||||
private val notificationActionListener: NotificationActionListener
|
private val notificationActionListener: NotificationActionListener,
|
||||||
|
private val linkListener: LinkListener
|
||||||
) : NotificationsPagingAdapter.ViewHolder, RecyclerView.ViewHolder(binding.root) {
|
) : NotificationsPagingAdapter.ViewHolder, RecyclerView.ViewHolder(binding.root) {
|
||||||
private val avatarRadius42dp = itemView.context.resources.getDimensionPixelSize(
|
private val avatarRadius42dp = itemView.context.resources.getDimensionPixelSize(
|
||||||
R.dimen.avatar_radius_42dp
|
R.dimen.avatar_radius_42dp
|
||||||
|
@ -94,11 +97,12 @@ class FollowViewHolder(
|
||||||
animateAvatars
|
animateAvatars
|
||||||
)
|
)
|
||||||
|
|
||||||
binding.notificationAccountNote.text = account.note.parseAsMastodonHtml().emojify(
|
val emojifiedNote = account.note.parseAsMastodonHtml().emojify(
|
||||||
account.emojis,
|
account.emojis,
|
||||||
binding.notificationAccountNote,
|
binding.notificationAccountNote,
|
||||||
animateEmojis
|
animateEmojis
|
||||||
)
|
)
|
||||||
|
setClickableText(binding.notificationAccountNote, emojifiedNote, emptyList(), null, linkListener)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setupButtons(listener: NotificationActionListener, accountId: String) {
|
private fun setupButtons(listener: NotificationActionListener, accountId: String) {
|
||||||
|
|
|
@ -147,13 +147,15 @@ class NotificationsPagingAdapter(
|
||||||
NotificationViewKind.FOLLOW -> {
|
NotificationViewKind.FOLLOW -> {
|
||||||
FollowViewHolder(
|
FollowViewHolder(
|
||||||
ItemFollowBinding.inflate(inflater, parent, false),
|
ItemFollowBinding.inflate(inflater, parent, false),
|
||||||
notificationActionListener
|
notificationActionListener,
|
||||||
|
statusActionListener
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
NotificationViewKind.FOLLOW_REQUEST -> {
|
NotificationViewKind.FOLLOW_REQUEST -> {
|
||||||
FollowRequestViewHolder(
|
FollowRequestViewHolder(
|
||||||
ItemFollowRequestBinding.inflate(inflater, parent, false),
|
ItemFollowRequestBinding.inflate(inflater, parent, false),
|
||||||
accountActionListener,
|
accountActionListener,
|
||||||
|
statusActionListener,
|
||||||
showHeader = true
|
showHeader = true
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,4 +16,6 @@
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
app:layout_behavior="@string/appbar_scrolling_view_behavior" />
|
app:layout_behavior="@string/appbar_scrolling_view_behavior" />
|
||||||
|
|
||||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
<include layout="@layout/item_status_bottom_sheet" />
|
||||||
|
|
||||||
|
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||||
|
|
|
@ -68,7 +68,7 @@
|
||||||
app:layout_constraintTop_toTopOf="@+id/notification_display_name"
|
app:layout_constraintTop_toTopOf="@+id/notification_display_name"
|
||||||
tools:text="\@testuser" />
|
tools:text="\@testuser" />
|
||||||
|
|
||||||
<TextView
|
<com.keylesspalace.tusky.view.ClickableSpanTextView
|
||||||
android:id="@+id/notification_account_note"
|
android:id="@+id/notification_account_note"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
|
|
@ -104,7 +104,7 @@
|
||||||
app:layout_constraintTop_toTopOf="@+id/rejectButton"
|
app:layout_constraintTop_toTopOf="@+id/rejectButton"
|
||||||
app:srcCompat="@drawable/ic_check_24dp" />
|
app:srcCompat="@drawable/ic_check_24dp" />
|
||||||
|
|
||||||
<TextView
|
<com.keylesspalace.tusky.view.ClickableSpanTextView
|
||||||
android:id="@+id/account_note"
|
android:id="@+id/account_note"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
|
Loading…
Add table
Reference in a new issue