mirror of
https://github.com/pachli/pachli-android.git
synced 2025-02-01 18:07:11 +01:00
refactor: Pass pachliAccountId to more functions (#1008)
While this isn't used in many places yet, it pushes the places where the active account is referenced further up the call stack.
This commit is contained in:
parent
ab186d4d07
commit
1b3b78a9dd
@ -29,23 +29,24 @@ import app.pachli.interfaces.StatusActionListener
|
||||
import app.pachli.viewdata.IStatusViewData
|
||||
|
||||
open class FilterableStatusViewHolder<T : IStatusViewData>(
|
||||
private val pachliAccountId: Long,
|
||||
private val binding: ItemStatusWrapperBinding,
|
||||
) : StatusViewHolder<T>(pachliAccountId, binding.statusContainer, binding.root) {
|
||||
) : StatusViewHolder<T>(binding.statusContainer, binding.root) {
|
||||
/** The filter that matched the status, null if the status is not being filtered. */
|
||||
var matchedFilter: Filter? = null
|
||||
|
||||
override fun setupWithStatus(
|
||||
pachliAccountId: Long,
|
||||
viewData: T,
|
||||
listener: StatusActionListener<T>,
|
||||
statusDisplayOptions: StatusDisplayOptions,
|
||||
payloads: Any?,
|
||||
) {
|
||||
super.setupWithStatus(viewData, listener, statusDisplayOptions, payloads)
|
||||
setupFilterPlaceholder(viewData, listener)
|
||||
super.setupWithStatus(pachliAccountId, viewData, listener, statusDisplayOptions, payloads)
|
||||
setupFilterPlaceholder(pachliAccountId, viewData, listener)
|
||||
}
|
||||
|
||||
private fun setupFilterPlaceholder(
|
||||
pachliAccountId: Long,
|
||||
status: T,
|
||||
listener: StatusActionListener<T>,
|
||||
) {
|
||||
@ -70,7 +71,7 @@ open class FilterableStatusViewHolder<T : IStatusViewData>(
|
||||
binding.statusFilteredPlaceholder.statusFilterLabel.text = label
|
||||
|
||||
binding.statusFilteredPlaceholder.statusFilterShowAnyway.setOnClickListener {
|
||||
listener.clearWarningAction(status)
|
||||
listener.clearWarningAction(pachliAccountId, status)
|
||||
}
|
||||
binding.statusFilteredPlaceholder.statusFilterEditFilter.setOnClickListener {
|
||||
listener.onEditFilterById(pachliAccountId, result.filter.id)
|
||||
|
@ -48,6 +48,7 @@ class FollowRequestViewHolder(
|
||||
) : NotificationsPagingAdapter.ViewHolder, RecyclerView.ViewHolder(binding.root) {
|
||||
|
||||
override fun bind(
|
||||
pachliAccountId: Long,
|
||||
viewData: NotificationViewData,
|
||||
payloads: List<*>?,
|
||||
statusDisplayOptions: StatusDisplayOptions,
|
||||
|
@ -41,6 +41,7 @@ class ReportNotificationViewHolder(
|
||||
) : NotificationsPagingAdapter.ViewHolder, RecyclerView.ViewHolder(binding.root) {
|
||||
|
||||
override fun bind(
|
||||
pachliAccountId: Long,
|
||||
viewData: NotificationViewData,
|
||||
payloads: List<*>?,
|
||||
statusDisplayOptions: StatusDisplayOptions,
|
||||
|
@ -64,7 +64,6 @@ import java.text.NumberFormat
|
||||
import java.util.Date
|
||||
|
||||
abstract class StatusBaseViewHolder<T : IStatusViewData> protected constructor(
|
||||
private val pachliAccountId: Long,
|
||||
itemView: View,
|
||||
) :
|
||||
RecyclerView.ViewHolder(itemView) {
|
||||
@ -146,6 +145,7 @@ abstract class StatusBaseViewHolder<T : IStatusViewData> protected constructor(
|
||||
}
|
||||
|
||||
protected fun setSpoilerAndContent(
|
||||
pachliAccountId: Long,
|
||||
viewData: T,
|
||||
statusDisplayOptions: StatusDisplayOptions,
|
||||
listener: StatusActionListener<T>,
|
||||
@ -165,6 +165,7 @@ abstract class StatusBaseViewHolder<T : IStatusViewData> protected constructor(
|
||||
setContentWarningButtonText(expanded)
|
||||
contentWarningButton.setOnClickListener {
|
||||
toggleExpandedState(
|
||||
pachliAccountId,
|
||||
viewData,
|
||||
true,
|
||||
!expanded,
|
||||
@ -196,6 +197,7 @@ abstract class StatusBaseViewHolder<T : IStatusViewData> protected constructor(
|
||||
}
|
||||
|
||||
protected open fun toggleExpandedState(
|
||||
pachliAccountId: Long,
|
||||
viewData: T,
|
||||
sensitive: Boolean,
|
||||
expanded: Boolean,
|
||||
@ -203,10 +205,11 @@ abstract class StatusBaseViewHolder<T : IStatusViewData> protected constructor(
|
||||
listener: StatusActionListener<T>,
|
||||
) {
|
||||
contentWarningDescription.invalidate()
|
||||
listener.onExpandedChange(viewData, expanded)
|
||||
listener.onExpandedChange(pachliAccountId, viewData, expanded)
|
||||
setContentWarningButtonText(expanded)
|
||||
setTextVisible(sensitive, expanded, viewData, statusDisplayOptions, listener)
|
||||
setupCard(
|
||||
pachliAccountId,
|
||||
viewData,
|
||||
expanded,
|
||||
statusDisplayOptions.cardViewMode,
|
||||
@ -463,6 +466,7 @@ abstract class StatusBaseViewHolder<T : IStatusViewData> protected constructor(
|
||||
}
|
||||
|
||||
protected fun setMediaPreviews(
|
||||
pachliAccountId: Long,
|
||||
viewData: T,
|
||||
attachments: List<Attachment>,
|
||||
sensitive: Boolean,
|
||||
@ -494,7 +498,7 @@ abstract class StatusBaseViewHolder<T : IStatusViewData> protected constructor(
|
||||
} else {
|
||||
imageView.foreground = null
|
||||
}
|
||||
setAttachmentClickListener(viewData, imageView, listener, i, attachment, true)
|
||||
setAttachmentClickListener(pachliAccountId, viewData, imageView, listener, i, attachment, true)
|
||||
if (sensitive) {
|
||||
sensitiveMediaWarning.setText(R.string.post_sensitive_media_title)
|
||||
} else {
|
||||
@ -505,13 +509,13 @@ abstract class StatusBaseViewHolder<T : IStatusViewData> protected constructor(
|
||||
descriptionIndicator.visibility =
|
||||
if (hasDescription && showingContent) View.VISIBLE else View.GONE
|
||||
sensitiveMediaShow.setOnClickListener { v: View ->
|
||||
listener.onContentHiddenChange(viewData, false)
|
||||
listener.onContentHiddenChange(pachliAccountId, viewData, false)
|
||||
v.visibility = View.GONE
|
||||
sensitiveMediaWarning.visibility = View.VISIBLE
|
||||
descriptionIndicator.visibility = View.GONE
|
||||
}
|
||||
sensitiveMediaWarning.setOnClickListener { v: View ->
|
||||
listener.onContentHiddenChange(viewData, true)
|
||||
listener.onContentHiddenChange(pachliAccountId, viewData, true)
|
||||
v.visibility = View.GONE
|
||||
sensitiveMediaShow.visibility = View.VISIBLE
|
||||
descriptionIndicator.visibility = if (hasDescription) View.VISIBLE else View.GONE
|
||||
@ -526,6 +530,7 @@ abstract class StatusBaseViewHolder<T : IStatusViewData> protected constructor(
|
||||
}
|
||||
|
||||
protected fun setMediaLabel(
|
||||
pachliAccountId: Long,
|
||||
viewData: T,
|
||||
attachments: List<Attachment>,
|
||||
sensitive: Boolean,
|
||||
@ -543,7 +548,7 @@ abstract class StatusBaseViewHolder<T : IStatusViewData> protected constructor(
|
||||
// Set the icon next to the label.
|
||||
val drawableId = attachments[0].iconResource()
|
||||
mediaLabel.setCompoundDrawablesRelativeWithIntrinsicBounds(drawableId, 0, 0, 0)
|
||||
setAttachmentClickListener(viewData, mediaLabel, listener, i, attachment, false)
|
||||
setAttachmentClickListener(pachliAccountId, viewData, mediaLabel, listener, i, attachment, false)
|
||||
} else {
|
||||
mediaLabel.visibility = View.GONE
|
||||
}
|
||||
@ -551,6 +556,7 @@ abstract class StatusBaseViewHolder<T : IStatusViewData> protected constructor(
|
||||
}
|
||||
|
||||
private fun setAttachmentClickListener(
|
||||
pachliAccountId: Long,
|
||||
viewData: T,
|
||||
view: View,
|
||||
listener: StatusActionListener<T>,
|
||||
@ -560,7 +566,7 @@ abstract class StatusBaseViewHolder<T : IStatusViewData> protected constructor(
|
||||
) {
|
||||
view.setOnClickListener { v: View? ->
|
||||
if (sensitiveMediaWarning.visibility == View.VISIBLE) {
|
||||
listener.onContentHiddenChange(viewData, true)
|
||||
listener.onContentHiddenChange(pachliAccountId, viewData, true)
|
||||
} else {
|
||||
listener.onViewMedia(viewData, index, if (animateTransition) v else null)
|
||||
}
|
||||
@ -676,6 +682,7 @@ abstract class StatusBaseViewHolder<T : IStatusViewData> protected constructor(
|
||||
}
|
||||
|
||||
open fun setupWithStatus(
|
||||
pachliAccountId: Long,
|
||||
viewData: T,
|
||||
listener: StatusActionListener<T>,
|
||||
statusDisplayOptions: StatusDisplayOptions,
|
||||
@ -707,6 +714,7 @@ abstract class StatusBaseViewHolder<T : IStatusViewData> protected constructor(
|
||||
val sensitive = actionable.sensitive
|
||||
if (statusDisplayOptions.mediaPreviewEnabled && hasPreviewableAttachment(attachments)) {
|
||||
setMediaPreviews(
|
||||
pachliAccountId,
|
||||
viewData,
|
||||
attachments,
|
||||
sensitive,
|
||||
@ -722,12 +730,13 @@ abstract class StatusBaseViewHolder<T : IStatusViewData> protected constructor(
|
||||
mediaLabel.visibility = View.GONE
|
||||
}
|
||||
} else {
|
||||
setMediaLabel(viewData, attachments, sensitive, listener, viewData.isShowingContent)
|
||||
setMediaLabel(pachliAccountId, viewData, attachments, sensitive, listener, viewData.isShowingContent)
|
||||
// Hide all unused views.
|
||||
mediaPreview.visibility = View.GONE
|
||||
hideSensitiveMediaWarning()
|
||||
}
|
||||
setupCard(
|
||||
pachliAccountId,
|
||||
viewData,
|
||||
viewData.isExpanded,
|
||||
statusDisplayOptions.cardViewMode,
|
||||
@ -741,7 +750,7 @@ abstract class StatusBaseViewHolder<T : IStatusViewData> protected constructor(
|
||||
statusDisplayOptions,
|
||||
)
|
||||
setRebloggingEnabled(actionable.rebloggingAllowed(), actionable.visibility)
|
||||
setSpoilerAndContent(viewData, statusDisplayOptions, listener)
|
||||
setSpoilerAndContent(pachliAccountId, viewData, statusDisplayOptions, listener)
|
||||
setContentDescriptionForStatus(viewData, statusDisplayOptions)
|
||||
|
||||
// Workaround for RecyclerView 1.0.0 / androidx.core 1.0.0
|
||||
@ -865,6 +874,7 @@ abstract class StatusBaseViewHolder<T : IStatusViewData> protected constructor(
|
||||
}
|
||||
|
||||
protected fun setupCard(
|
||||
pachliAccountId: Long,
|
||||
viewData: T,
|
||||
expanded: Boolean,
|
||||
cardViewMode: CardViewMode,
|
||||
|
@ -23,9 +23,8 @@ import java.text.DateFormat
|
||||
import java.util.Locale
|
||||
|
||||
class StatusDetailedViewHolder(
|
||||
pachliAccountId: Long,
|
||||
private val binding: ItemStatusDetailedBinding,
|
||||
) : StatusBaseViewHolder<StatusViewData>(pachliAccountId, binding.root) {
|
||||
) : StatusBaseViewHolder<StatusViewData>(binding.root) {
|
||||
|
||||
override fun setMetaData(
|
||||
viewData: StatusViewData,
|
||||
@ -107,6 +106,7 @@ class StatusDetailedViewHolder(
|
||||
}
|
||||
|
||||
override fun setupWithStatus(
|
||||
pachliAccountId: Long,
|
||||
viewData: StatusViewData,
|
||||
listener: StatusActionListener<StatusViewData>,
|
||||
statusDisplayOptions: StatusDisplayOptions,
|
||||
@ -115,8 +115,9 @@ class StatusDetailedViewHolder(
|
||||
// We never collapse statuses in the detail view
|
||||
val uncollapsedStatus =
|
||||
if (viewData.isCollapsible && viewData.isCollapsed) viewData.copy(isCollapsed = false) else viewData
|
||||
super.setupWithStatus(uncollapsedStatus, listener, statusDisplayOptions, payloads)
|
||||
super.setupWithStatus(pachliAccountId, uncollapsedStatus, listener, statusDisplayOptions, payloads)
|
||||
setupCard(
|
||||
pachliAccountId,
|
||||
uncollapsedStatus,
|
||||
viewData.isExpanded,
|
||||
CardViewMode.FULL_WIDTH,
|
||||
|
@ -36,12 +36,12 @@ import app.pachli.viewdata.IStatusViewData
|
||||
import at.connyduck.sparkbutton.helpers.Utils
|
||||
|
||||
open class StatusViewHolder<T : IStatusViewData>(
|
||||
pachliAccountId: Long,
|
||||
private val binding: ItemStatusBinding,
|
||||
root: View? = null,
|
||||
) : StatusBaseViewHolder<T>(pachliAccountId, root ?: binding.root) {
|
||||
) : StatusBaseViewHolder<T>(root ?: binding.root) {
|
||||
|
||||
override fun setupWithStatus(
|
||||
pachliAccountId: Long,
|
||||
viewData: T,
|
||||
listener: StatusActionListener<T>,
|
||||
statusDisplayOptions: StatusDisplayOptions,
|
||||
@ -50,7 +50,7 @@ open class StatusViewHolder<T : IStatusViewData>(
|
||||
if (payloads == null) {
|
||||
val sensitive = !TextUtils.isEmpty(viewData.actionable.spoilerText)
|
||||
val expanded = viewData.isExpanded
|
||||
setupCollapsedState(viewData, sensitive, expanded, listener)
|
||||
setupCollapsedState(pachliAccountId, viewData, sensitive, expanded, listener)
|
||||
val reblogging = viewData.rebloggingStatus
|
||||
if (reblogging == null || viewData.filterAction === FilterAction.WARN) {
|
||||
statusInfo.hide()
|
||||
@ -70,7 +70,7 @@ open class StatusViewHolder<T : IStatusViewData>(
|
||||
statusFavouritesCount.visible(statusDisplayOptions.showStatsInline)
|
||||
setFavouritedCount(viewData.actionable.favouritesCount)
|
||||
setReblogsCount(viewData.actionable.reblogsCount)
|
||||
super.setupWithStatus(viewData, listener, statusDisplayOptions, payloads)
|
||||
super.setupWithStatus(pachliAccountId, viewData, listener, statusDisplayOptions, payloads)
|
||||
}
|
||||
|
||||
private fun setRebloggedByDisplayName(
|
||||
@ -109,6 +109,7 @@ open class StatusViewHolder<T : IStatusViewData>(
|
||||
}
|
||||
|
||||
private fun setupCollapsedState(
|
||||
pachliAccountId: Long,
|
||||
viewData: T,
|
||||
sensitive: Boolean,
|
||||
expanded: Boolean,
|
||||
@ -117,7 +118,7 @@ open class StatusViewHolder<T : IStatusViewData>(
|
||||
/* input filter for TextViews have to be set before text */
|
||||
if (viewData.isCollapsible && (!sensitive || expanded)) {
|
||||
buttonToggleContent.setOnClickListener {
|
||||
listener.onContentCollapsedChange(viewData, !viewData.isCollapsed)
|
||||
listener.onContentCollapsedChange(pachliAccountId, viewData, !viewData.isCollapsed)
|
||||
}
|
||||
buttonToggleContent.show()
|
||||
if (viewData.isCollapsed) {
|
||||
@ -139,14 +140,15 @@ open class StatusViewHolder<T : IStatusViewData>(
|
||||
}
|
||||
|
||||
override fun toggleExpandedState(
|
||||
pachliAccountId: Long,
|
||||
viewData: T,
|
||||
sensitive: Boolean,
|
||||
expanded: Boolean,
|
||||
statusDisplayOptions: StatusDisplayOptions,
|
||||
listener: StatusActionListener<T>,
|
||||
) {
|
||||
setupCollapsedState(viewData, sensitive, expanded, listener)
|
||||
super.toggleExpandedState(viewData, sensitive, expanded, statusDisplayOptions, listener)
|
||||
setupCollapsedState(pachliAccountId, viewData, sensitive, expanded, listener)
|
||||
super.toggleExpandedState(pachliAccountId, viewData, sensitive, expanded, statusDisplayOptions, listener)
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
@ -41,7 +41,7 @@ class ConversationAdapter(
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ConversationViewHolder {
|
||||
val view = LayoutInflater.from(parent.context).inflate(R.layout.item_conversation, parent, false)
|
||||
return ConversationViewHolder(pachliAccountId, view, statusDisplayOptions, listener)
|
||||
return ConversationViewHolder(view, statusDisplayOptions, listener)
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: ConversationViewHolder, position: Int) {
|
||||
@ -54,7 +54,7 @@ class ConversationAdapter(
|
||||
payloads: List<Any>,
|
||||
) {
|
||||
getItem(position)?.let { conversationViewData ->
|
||||
holder.setupWithConversation(conversationViewData, payloads.firstOrNull())
|
||||
holder.setupWithConversation(pachliAccountId, conversationViewData, payloads.firstOrNull())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -33,11 +33,10 @@ import app.pachli.interfaces.StatusActionListener
|
||||
import app.pachli.util.SmartLengthInputFilter
|
||||
|
||||
class ConversationViewHolder internal constructor(
|
||||
pachliAccountId: Long,
|
||||
itemView: View,
|
||||
private val statusDisplayOptions: StatusDisplayOptions,
|
||||
private val listener: StatusActionListener<ConversationViewData>,
|
||||
) : StatusBaseViewHolder<ConversationViewData>(pachliAccountId, itemView) {
|
||||
) : StatusBaseViewHolder<ConversationViewData>(itemView) {
|
||||
private val conversationNameTextView: TextView = itemView.findViewById(R.id.conversation_name)
|
||||
private val contentCollapseButton: Button = itemView.findViewById(R.id.button_toggle_content)
|
||||
private val avatars: Array<ImageView> = arrayOf(
|
||||
@ -47,12 +46,13 @@ class ConversationViewHolder internal constructor(
|
||||
)
|
||||
|
||||
fun setupWithConversation(
|
||||
pachliAccountId: Long,
|
||||
viewData: ConversationViewData,
|
||||
payloads: Any?,
|
||||
) {
|
||||
val (_, _, account, inReplyToId, _, _, _, _, _, _, _, _, _, _, favourited, bookmarked, sensitive, _, _, attachments) = viewData.status
|
||||
if (payloads == null) {
|
||||
setupCollapsedState(viewData, listener)
|
||||
setupCollapsedState(pachliAccountId, viewData, listener)
|
||||
setDisplayName(account.name, account.emojis, statusDisplayOptions)
|
||||
setUsername(account.username)
|
||||
setMetaData(viewData, statusDisplayOptions, listener)
|
||||
@ -61,6 +61,7 @@ class ConversationViewHolder internal constructor(
|
||||
setBookmarked(bookmarked)
|
||||
if (statusDisplayOptions.mediaPreviewEnabled && hasPreviewableAttachment(attachments)) {
|
||||
setMediaPreviews(
|
||||
pachliAccountId,
|
||||
viewData,
|
||||
attachments,
|
||||
sensitive,
|
||||
@ -76,7 +77,7 @@ class ConversationViewHolder internal constructor(
|
||||
mediaLabel.visibility = View.GONE
|
||||
}
|
||||
} else {
|
||||
setMediaLabel(viewData, attachments, sensitive, listener, viewData.isShowingContent)
|
||||
setMediaLabel(pachliAccountId, viewData, attachments, sensitive, listener, viewData.isShowingContent)
|
||||
// Hide all unused views.
|
||||
mediaPreview.visibility = View.GONE
|
||||
hideSensitiveMediaWarning()
|
||||
@ -87,7 +88,7 @@ class ConversationViewHolder internal constructor(
|
||||
account.id,
|
||||
statusDisplayOptions,
|
||||
)
|
||||
setSpoilerAndContent(viewData, statusDisplayOptions, listener)
|
||||
setSpoilerAndContent(pachliAccountId, viewData, statusDisplayOptions, listener)
|
||||
setConversationName(viewData.accounts)
|
||||
setAvatars(viewData.accounts)
|
||||
} else {
|
||||
@ -137,13 +138,14 @@ class ConversationViewHolder internal constructor(
|
||||
}
|
||||
|
||||
private fun setupCollapsedState(
|
||||
pachliAccountId: Long,
|
||||
viewData: ConversationViewData,
|
||||
listener: StatusActionListener<ConversationViewData>,
|
||||
) {
|
||||
/* input filter for TextViews have to be set before text */
|
||||
if (viewData.isCollapsible && (viewData.isExpanded || TextUtils.isEmpty(viewData.spoilerText))) {
|
||||
contentCollapseButton.setOnClickListener {
|
||||
listener.onContentCollapsedChange(viewData, !viewData.isCollapsed)
|
||||
listener.onContentCollapsedChange(pachliAccountId, viewData, !viewData.isCollapsed)
|
||||
}
|
||||
contentCollapseButton.show()
|
||||
if (viewData.isCollapsed) {
|
||||
|
@ -322,16 +322,16 @@ class ConversationsFragment :
|
||||
// there are no reblogs in conversations
|
||||
}
|
||||
|
||||
override fun onExpandedChange(viewData: ConversationViewData, expanded: Boolean) {
|
||||
viewModel.expandHiddenStatus(expanded, viewData.lastStatus.id)
|
||||
override fun onExpandedChange(pachliAccountId: Long, viewData: ConversationViewData, expanded: Boolean) {
|
||||
viewModel.expandHiddenStatus(pachliAccountId, expanded, viewData.lastStatus.id)
|
||||
}
|
||||
|
||||
override fun onContentHiddenChange(viewData: ConversationViewData, isShowing: Boolean) {
|
||||
viewModel.showContent(isShowing, viewData.lastStatus.id)
|
||||
override fun onContentHiddenChange(pachliAccountId: Long, viewData: ConversationViewData, isShowing: Boolean) {
|
||||
viewModel.showContent(pachliAccountId, isShowing, viewData.lastStatus.id)
|
||||
}
|
||||
|
||||
override fun onContentCollapsedChange(viewData: ConversationViewData, isCollapsed: Boolean) {
|
||||
viewModel.collapseLongStatus(isCollapsed, viewData.lastStatus.id)
|
||||
override fun onContentCollapsedChange(pachliAccountId: Long, viewData: ConversationViewData, isCollapsed: Boolean) {
|
||||
viewModel.collapseLongStatus(pachliAccountId, isCollapsed, viewData.lastStatus.id)
|
||||
}
|
||||
|
||||
override fun onViewAccount(id: String) {
|
||||
@ -356,7 +356,7 @@ class ConversationsFragment :
|
||||
viewModel.voteInPoll(choices, viewData.lastStatus.actionableId, poll.id)
|
||||
}
|
||||
|
||||
override fun clearWarningAction(viewData: ConversationViewData) {
|
||||
override fun clearWarningAction(pachliAccountId: Long, viewData: ConversationViewData) {
|
||||
}
|
||||
|
||||
// Filters don't apply in conversations
|
||||
|
@ -136,30 +136,30 @@ class ConversationsViewModel @Inject constructor(
|
||||
}
|
||||
}
|
||||
|
||||
fun expandHiddenStatus(expanded: Boolean, lastStatusId: String) {
|
||||
fun expandHiddenStatus(pachliAccountId: Long, expanded: Boolean, lastStatusId: String) {
|
||||
viewModelScope.launch {
|
||||
conversationsDao.setExpanded(
|
||||
accountManager.activeAccount!!.id,
|
||||
pachliAccountId,
|
||||
lastStatusId,
|
||||
expanded,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun collapseLongStatus(collapsed: Boolean, lastStatusId: String) {
|
||||
fun collapseLongStatus(pachliAccountId: Long, collapsed: Boolean, lastStatusId: String) {
|
||||
viewModelScope.launch {
|
||||
conversationsDao.setCollapsed(
|
||||
accountManager.activeAccount!!.id,
|
||||
pachliAccountId,
|
||||
lastStatusId,
|
||||
collapsed,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun showContent(showingHiddenContent: Boolean, lastStatusId: String) {
|
||||
fun showContent(pachliAccountId: Long, showingHiddenContent: Boolean, lastStatusId: String) {
|
||||
viewModelScope.launch {
|
||||
conversationsDao.setShowingHiddenContent(
|
||||
accountManager.activeAccount!!.id,
|
||||
pachliAccountId,
|
||||
lastStatusId,
|
||||
showingHiddenContent,
|
||||
)
|
||||
|
@ -42,6 +42,7 @@ class FollowViewHolder(
|
||||
)
|
||||
|
||||
override fun bind(
|
||||
pachliAccountId: Long,
|
||||
viewData: NotificationViewData,
|
||||
payloads: List<*>?,
|
||||
statusDisplayOptions: StatusDisplayOptions,
|
||||
|
@ -568,7 +568,7 @@ class NotificationsFragment :
|
||||
onViewAccount(status.account.id)
|
||||
}
|
||||
|
||||
override fun onExpandedChange(viewData: NotificationViewData, expanded: Boolean) {
|
||||
override fun onExpandedChange(pachliAccountId: Long, viewData: NotificationViewData, expanded: Boolean) {
|
||||
adapter.snapshot().withIndex()
|
||||
.filter {
|
||||
it.value?.statusViewData?.actionableId == viewData.statusViewData!!.actionableId
|
||||
@ -579,7 +579,7 @@ class NotificationsFragment :
|
||||
}
|
||||
}
|
||||
|
||||
override fun onContentHiddenChange(viewData: NotificationViewData, isShowing: Boolean) {
|
||||
override fun onContentHiddenChange(pachliAccountId: Long, viewData: NotificationViewData, isShowing: Boolean) {
|
||||
adapter.snapshot().withIndex()
|
||||
.filter {
|
||||
it.value?.statusViewData?.actionableId == viewData.statusViewData!!.actionableId
|
||||
@ -590,7 +590,7 @@ class NotificationsFragment :
|
||||
}
|
||||
}
|
||||
|
||||
override fun onContentCollapsedChange(viewData: NotificationViewData, isCollapsed: Boolean) {
|
||||
override fun onContentCollapsedChange(pachliAccountId: Long, viewData: NotificationViewData, isCollapsed: Boolean) {
|
||||
adapter.snapshot().withIndex().filter {
|
||||
it.value?.statusViewData?.actionableId == viewData.statusViewData!!.actionableId
|
||||
}
|
||||
@ -608,13 +608,14 @@ class NotificationsFragment :
|
||||
}
|
||||
|
||||
override fun onNotificationContentCollapsedChange(
|
||||
pachliAccountId: Long,
|
||||
isCollapsed: Boolean,
|
||||
viewData: NotificationViewData,
|
||||
) {
|
||||
onContentCollapsedChange(viewData, isCollapsed)
|
||||
onContentCollapsedChange(pachliAccountId, viewData, isCollapsed)
|
||||
}
|
||||
|
||||
override fun clearWarningAction(viewData: NotificationViewData) {
|
||||
override fun clearWarningAction(pachliAccountId: Long, viewData: NotificationViewData) {
|
||||
adapter.snapshot().withIndex().filter { it.value?.statusViewData?.actionableId == viewData.statusViewData!!.actionableId }
|
||||
.map {
|
||||
it.value?.statusViewData = it.value?.statusViewData?.copy(
|
||||
|
@ -94,7 +94,7 @@ interface NotificationActionListener {
|
||||
* @param expanded the desired state of the content behind the content warning
|
||||
*
|
||||
*/
|
||||
fun onExpandedChange(viewData: NotificationViewData, expanded: Boolean)
|
||||
fun onExpandedChange(pachliAccountId: Long, viewData: NotificationViewData, expanded: Boolean)
|
||||
|
||||
/**
|
||||
* Called when the status [android.widget.ToggleButton] responsible for collapsing long
|
||||
@ -103,6 +103,7 @@ interface NotificationActionListener {
|
||||
* @param isCollapsed Whether the status content is shown in a collapsed state or fully.
|
||||
*/
|
||||
fun onNotificationContentCollapsedChange(
|
||||
pachliAccountId: Long,
|
||||
isCollapsed: Boolean,
|
||||
viewData: NotificationViewData,
|
||||
)
|
||||
@ -125,6 +126,7 @@ class NotificationsPagingAdapter(
|
||||
interface ViewHolder {
|
||||
/** Bind the data from the notification and payloads to the view */
|
||||
fun bind(
|
||||
pachliAccountId: Long,
|
||||
viewData: NotificationViewData,
|
||||
payloads: List<*>?,
|
||||
statusDisplayOptions: StatusDisplayOptions,
|
||||
@ -146,7 +148,6 @@ class NotificationsPagingAdapter(
|
||||
return when (NotificationViewKind.entries[viewType]) {
|
||||
NotificationViewKind.STATUS -> {
|
||||
StatusViewHolder(
|
||||
pachliAccountId,
|
||||
ItemStatusBinding.inflate(inflater, parent, false),
|
||||
statusActionListener,
|
||||
accountId,
|
||||
@ -154,7 +155,6 @@ class NotificationsPagingAdapter(
|
||||
}
|
||||
NotificationViewKind.STATUS_FILTERED -> {
|
||||
FilterableStatusViewHolder(
|
||||
pachliAccountId,
|
||||
ItemStatusWrapperBinding.inflate(inflater, parent, false),
|
||||
statusActionListener,
|
||||
accountId,
|
||||
@ -203,7 +203,7 @@ class NotificationsPagingAdapter(
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
|
||||
bindViewHolder(holder, position, null)
|
||||
bindViewHolder(pachliAccountId, holder, position, null)
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(
|
||||
@ -211,15 +211,16 @@ class NotificationsPagingAdapter(
|
||||
position: Int,
|
||||
payloads: MutableList<Any>,
|
||||
) {
|
||||
bindViewHolder(holder, position, payloads)
|
||||
bindViewHolder(pachliAccountId, holder, position, payloads)
|
||||
}
|
||||
|
||||
private fun bindViewHolder(
|
||||
pachliAccountId: Long,
|
||||
holder: RecyclerView.ViewHolder,
|
||||
position: Int,
|
||||
payloads: List<*>?,
|
||||
) {
|
||||
getItem(position)?.let { (holder as ViewHolder).bind(it, payloads, statusDisplayOptions) }
|
||||
getItem(position)?.let { (holder as ViewHolder).bind(pachliAccountId, it, payloads, statusDisplayOptions) }
|
||||
}
|
||||
|
||||
/**
|
||||
@ -230,6 +231,7 @@ class NotificationsPagingAdapter(
|
||||
val binding: SimpleListItem1Binding,
|
||||
) : ViewHolder, RecyclerView.ViewHolder(binding.root) {
|
||||
override fun bind(
|
||||
pachliAccountId: Long,
|
||||
viewData: NotificationViewData,
|
||||
payloads: List<*>?,
|
||||
statusDisplayOptions: StatusDisplayOptions,
|
||||
|
@ -30,7 +30,12 @@ import app.pachli.viewdata.NotificationViewData
|
||||
class SeveredRelationshipsViewHolder(
|
||||
private val binding: ItemSeveredRelationshipsBinding,
|
||||
) : NotificationsPagingAdapter.ViewHolder, RecyclerView.ViewHolder(binding.root) {
|
||||
override fun bind(viewData: NotificationViewData, payloads: List<*>?, statusDisplayOptions: StatusDisplayOptions) {
|
||||
override fun bind(
|
||||
pachliAccountId: Long,
|
||||
viewData: NotificationViewData,
|
||||
payloads: List<*>?,
|
||||
statusDisplayOptions: StatusDisplayOptions,
|
||||
) {
|
||||
val event = viewData.relationshipSeveranceEvent!!
|
||||
if (payloads.isNullOrEmpty()) {
|
||||
binding.notificationTopText.text = HtmlCompat.fromHtml(
|
||||
|
@ -81,6 +81,7 @@ internal class StatusNotificationViewHolder(
|
||||
)
|
||||
|
||||
override fun bind(
|
||||
pachliAccountId: Long,
|
||||
viewData: NotificationViewData,
|
||||
payloads: List<*>?,
|
||||
statusDisplayOptions: StatusDisplayOptions,
|
||||
@ -124,7 +125,7 @@ internal class StatusNotificationViewHolder(
|
||||
notificationActionListener.onViewAccount(viewData.account.id)
|
||||
}
|
||||
}
|
||||
setMessage(viewData, statusActionListener, statusDisplayOptions.animateEmojis)
|
||||
setMessage(pachliAccountId, viewData, statusActionListener, statusDisplayOptions.animateEmojis)
|
||||
} else {
|
||||
for (item in payloads) {
|
||||
if (StatusBaseViewHolder.Key.KEY_CREATED == item && statusViewData != null) {
|
||||
@ -238,6 +239,7 @@ internal class StatusNotificationViewHolder(
|
||||
}
|
||||
|
||||
fun setMessage(
|
||||
pachliAccountId: Long,
|
||||
viewData: NotificationViewData,
|
||||
listener: LinkListener,
|
||||
animateEmojis: Boolean,
|
||||
@ -311,6 +313,7 @@ internal class StatusNotificationViewHolder(
|
||||
binding.notificationContentWarningButton.setOnClickListener {
|
||||
if (bindingAdapterPosition != RecyclerView.NO_POSITION) {
|
||||
notificationActionListener.onExpandedChange(
|
||||
pachliAccountId,
|
||||
viewData,
|
||||
!statusViewData.isExpanded,
|
||||
)
|
||||
@ -318,10 +321,11 @@ internal class StatusNotificationViewHolder(
|
||||
binding.notificationContent.visibility =
|
||||
if (statusViewData.isExpanded) View.GONE else View.VISIBLE
|
||||
}
|
||||
setupContentAndSpoiler(listener, viewData, statusViewData, animateEmojis)
|
||||
setupContentAndSpoiler(pachliAccountId, listener, viewData, statusViewData, animateEmojis)
|
||||
}
|
||||
|
||||
private fun setupContentAndSpoiler(
|
||||
pachliAccountId: Long,
|
||||
listener: LinkListener,
|
||||
viewData: NotificationViewData,
|
||||
statusViewData: StatusViewData,
|
||||
@ -341,6 +345,7 @@ internal class StatusNotificationViewHolder(
|
||||
val position = bindingAdapterPosition
|
||||
if (position != RecyclerView.NO_POSITION) {
|
||||
notificationActionListener.onNotificationContentCollapsedChange(
|
||||
pachliAccountId,
|
||||
!statusViewData.isCollapsed,
|
||||
viewData,
|
||||
)
|
||||
|
@ -27,13 +27,13 @@ import app.pachli.interfaces.StatusActionListener
|
||||
import app.pachli.viewdata.NotificationViewData
|
||||
|
||||
internal class StatusViewHolder(
|
||||
pachliAccountId: Long,
|
||||
binding: ItemStatusBinding,
|
||||
private val statusActionListener: StatusActionListener<NotificationViewData>,
|
||||
private val accountId: String,
|
||||
) : NotificationsPagingAdapter.ViewHolder, StatusViewHolder<NotificationViewData>(pachliAccountId, binding) {
|
||||
) : NotificationsPagingAdapter.ViewHolder, StatusViewHolder<NotificationViewData>(binding) {
|
||||
|
||||
override fun bind(
|
||||
pachliAccountId: Long,
|
||||
viewData: NotificationViewData,
|
||||
payloads: List<*>?,
|
||||
statusDisplayOptions: StatusDisplayOptions,
|
||||
@ -48,6 +48,7 @@ internal class StatusViewHolder(
|
||||
showStatusContent(true)
|
||||
}
|
||||
setupWithStatus(
|
||||
pachliAccountId,
|
||||
viewData,
|
||||
statusActionListener,
|
||||
statusDisplayOptions,
|
||||
@ -63,13 +64,13 @@ internal class StatusViewHolder(
|
||||
}
|
||||
|
||||
class FilterableStatusViewHolder(
|
||||
private val pachliAccountId: Long,
|
||||
binding: ItemStatusWrapperBinding,
|
||||
private val statusActionListener: StatusActionListener<NotificationViewData>,
|
||||
private val accountId: String,
|
||||
) : NotificationsPagingAdapter.ViewHolder, FilterableStatusViewHolder<NotificationViewData>(pachliAccountId, binding) {
|
||||
) : NotificationsPagingAdapter.ViewHolder, FilterableStatusViewHolder<NotificationViewData>(binding) {
|
||||
// Note: Identical to bind() in StatusViewHolder above
|
||||
override fun bind(
|
||||
pachliAccountId: Long,
|
||||
viewData: NotificationViewData,
|
||||
payloads: List<*>?,
|
||||
statusDisplayOptions: StatusDisplayOptions,
|
||||
@ -84,6 +85,7 @@ class FilterableStatusViewHolder(
|
||||
showStatusContent(true)
|
||||
}
|
||||
setupWithStatus(
|
||||
pachliAccountId,
|
||||
viewData,
|
||||
statusActionListener,
|
||||
statusDisplayOptions,
|
||||
|
@ -34,14 +34,13 @@ class SearchStatusesAdapter(
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): StatusViewHolder<StatusViewData> {
|
||||
return StatusViewHolder(
|
||||
pachliAccountId,
|
||||
ItemStatusBinding.inflate(LayoutInflater.from(parent.context), parent, false),
|
||||
)
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: StatusViewHolder<StatusViewData>, position: Int) {
|
||||
getItem(position)?.let { item ->
|
||||
holder.setupWithStatus(item, statusListener, statusDisplayOptions)
|
||||
holder.setupWithStatus(pachliAccountId, item, statusListener, statusDisplayOptions)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -88,7 +88,7 @@ class SearchStatusesFragment : SearchFragment<StatusViewData>(), StatusActionLis
|
||||
return SearchStatusesAdapter(viewModel.activeAccount!!.id, statusDisplayOptions, this)
|
||||
}
|
||||
|
||||
override fun onContentHiddenChange(viewData: StatusViewData, isShowing: Boolean) {
|
||||
override fun onContentHiddenChange(pachliAccountId: Long, viewData: StatusViewData, isShowing: Boolean) {
|
||||
viewModel.contentHiddenChange(viewData, isShowing)
|
||||
}
|
||||
|
||||
@ -148,11 +148,11 @@ class SearchStatusesFragment : SearchFragment<StatusViewData>(), StatusActionLis
|
||||
bottomSheetActivity?.viewAccount(pachliAccountId, status.account.id)
|
||||
}
|
||||
|
||||
override fun onExpandedChange(viewData: StatusViewData, expanded: Boolean) {
|
||||
override fun onExpandedChange(pachliAccountId: Long, viewData: StatusViewData, expanded: Boolean) {
|
||||
viewModel.expandedChange(viewData, expanded)
|
||||
}
|
||||
|
||||
override fun onContentCollapsedChange(viewData: StatusViewData, isCollapsed: Boolean) {
|
||||
override fun onContentCollapsedChange(pachliAccountId: Long, viewData: StatusViewData, isCollapsed: Boolean) {
|
||||
viewModel.collapsedChange(viewData, isCollapsed)
|
||||
}
|
||||
|
||||
@ -160,7 +160,7 @@ class SearchStatusesFragment : SearchFragment<StatusViewData>(), StatusActionLis
|
||||
viewModel.voteInPoll(viewData, poll, choices)
|
||||
}
|
||||
|
||||
override fun clearWarningAction(viewData: StatusViewData) {}
|
||||
override fun clearWarningAction(pachliAccountId: Long, viewData: StatusViewData) {}
|
||||
|
||||
override fun onReblog(viewData: StatusViewData, reblog: Boolean) {
|
||||
viewModel.reblog(viewData, reblog)
|
||||
|
@ -126,21 +126,21 @@ class CachedTimelineRepository @Inject constructor(
|
||||
}
|
||||
|
||||
/** Invalidate the active paging source, see [androidx.paging.PagingSource.invalidate] */
|
||||
suspend fun invalidate() {
|
||||
suspend fun invalidate(pachliAccountId: Long) {
|
||||
// Invalidating when no statuses have been loaded can cause empty timelines because it
|
||||
// cancels the network load.
|
||||
if (timelineDao.getStatusCount(activeAccount!!.id) < 1) {
|
||||
if (timelineDao.getStatusCount(pachliAccountId) < 1) {
|
||||
return
|
||||
}
|
||||
|
||||
factory?.invalidate()
|
||||
}
|
||||
|
||||
suspend fun saveStatusViewData(statusViewData: StatusViewData) = externalScope.launch {
|
||||
suspend fun saveStatusViewData(pachliAccountId: Long, statusViewData: StatusViewData) = externalScope.launch {
|
||||
timelineDao.upsertStatusViewData(
|
||||
StatusViewDataEntity(
|
||||
serverId = statusViewData.actionableId,
|
||||
timelineUserId = activeAccount!!.id,
|
||||
timelineUserId = pachliAccountId,
|
||||
expanded = statusViewData.isExpanded,
|
||||
contentShowing = statusViewData.isShowingContent,
|
||||
contentCollapsed = statusViewData.isCollapsed,
|
||||
@ -152,74 +152,75 @@ class CachedTimelineRepository @Inject constructor(
|
||||
/**
|
||||
* @return Map between statusIDs and any viewdata for them cached in the repository.
|
||||
*/
|
||||
suspend fun getStatusViewData(statusId: List<String>): Map<String, StatusViewDataEntity> {
|
||||
return timelineDao.getStatusViewData(activeAccount!!.id, statusId)
|
||||
suspend fun getStatusViewData(pachliAccountId: Long, statusId: List<String>): Map<String, StatusViewDataEntity> {
|
||||
return timelineDao.getStatusViewData(pachliAccountId, statusId)
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Map between statusIDs and any translations for them cached in the repository.
|
||||
*/
|
||||
suspend fun getStatusTranslations(statusIds: List<String>): Map<String, TranslatedStatusEntity> {
|
||||
return translatedStatusDao.getTranslations(activeAccount!!.id, statusIds)
|
||||
suspend fun getStatusTranslations(pachliAccountId: Long, statusIds: List<String>): Map<String, TranslatedStatusEntity> {
|
||||
return translatedStatusDao.getTranslations(pachliAccountId, statusIds)
|
||||
}
|
||||
|
||||
/** Remove all statuses authored/boosted by the given account, for the active account */
|
||||
suspend fun removeAllByAccountId(accountId: String) = externalScope.launch {
|
||||
timelineDao.removeAllByUser(activeAccount!!.id, accountId)
|
||||
suspend fun removeAllByAccountId(pachliAccountId: Long, accountId: String) = externalScope.launch {
|
||||
timelineDao.removeAllByUser(pachliAccountId, accountId)
|
||||
}.join()
|
||||
|
||||
/** Remove all statuses from the given instance, for the active account */
|
||||
suspend fun removeAllByInstance(instance: String) = externalScope.launch {
|
||||
timelineDao.deleteAllFromInstance(activeAccount!!.id, instance)
|
||||
suspend fun removeAllByInstance(pachliAccountId: Long, instance: String) = externalScope.launch {
|
||||
timelineDao.deleteAllFromInstance(pachliAccountId, instance)
|
||||
}.join()
|
||||
|
||||
/** Clear the warning (remove the "filtered" setting) for the given status, for the active account */
|
||||
suspend fun clearStatusWarning(statusId: String) = externalScope.launch {
|
||||
timelineDao.clearWarning(activeAccount!!.id, statusId)
|
||||
suspend fun clearStatusWarning(pachliAccountId: Long, statusId: String) = externalScope.launch {
|
||||
timelineDao.clearWarning(pachliAccountId, statusId)
|
||||
}.join()
|
||||
|
||||
/** Remove all statuses and invalidate the pager, for the active account */
|
||||
suspend fun clearAndReload() = externalScope.launch {
|
||||
suspend fun clearAndReload(pachliAccountId: Long) = externalScope.launch {
|
||||
Timber.d("clearAndReload()")
|
||||
timelineDao.removeAll(activeAccount!!.id)
|
||||
timelineDao.removeAll(pachliAccountId)
|
||||
factory?.invalidate()
|
||||
}.join()
|
||||
|
||||
suspend fun clearAndReloadFromNewest() = externalScope.launch {
|
||||
activeAccount?.let {
|
||||
timelineDao.removeAll(it.id)
|
||||
remoteKeyDao.delete(it.id)
|
||||
invalidate()
|
||||
}
|
||||
suspend fun clearAndReloadFromNewest(pachliAccountId: Long) = externalScope.launch {
|
||||
timelineDao.removeAll(pachliAccountId)
|
||||
remoteKeyDao.delete(pachliAccountId)
|
||||
invalidate(pachliAccountId)
|
||||
}
|
||||
|
||||
suspend fun translate(statusViewData: StatusViewData): NetworkResult<Translation> {
|
||||
saveStatusViewData(statusViewData.copy(translationState = TranslationState.TRANSLATING))
|
||||
suspend fun translate(pachliAccountId: Long, statusViewData: StatusViewData): NetworkResult<Translation> {
|
||||
saveStatusViewData(pachliAccountId, statusViewData.copy(translationState = TranslationState.TRANSLATING))
|
||||
val translation = mastodonApi.translate(statusViewData.actionableId)
|
||||
translation.fold({
|
||||
translatedStatusDao.upsert(
|
||||
TranslatedStatusEntity(
|
||||
serverId = statusViewData.actionableId,
|
||||
timelineUserId = activeAccount!!.id,
|
||||
// TODO: Should this embed the network type instead of copying data
|
||||
// from one type to another?
|
||||
content = it.content,
|
||||
spoilerText = it.spoilerText,
|
||||
poll = it.poll,
|
||||
attachments = it.attachments,
|
||||
provider = it.provider,
|
||||
),
|
||||
)
|
||||
saveStatusViewData(statusViewData.copy(translationState = TranslationState.SHOW_TRANSLATION))
|
||||
}, {
|
||||
// Reset the translation state
|
||||
saveStatusViewData(statusViewData)
|
||||
})
|
||||
translation.fold(
|
||||
{
|
||||
translatedStatusDao.upsert(
|
||||
TranslatedStatusEntity(
|
||||
serverId = statusViewData.actionableId,
|
||||
timelineUserId = pachliAccountId,
|
||||
// TODO: Should this embed the network type instead of copying data
|
||||
// from one type to another?
|
||||
content = it.content,
|
||||
spoilerText = it.spoilerText,
|
||||
poll = it.poll,
|
||||
attachments = it.attachments,
|
||||
provider = it.provider,
|
||||
),
|
||||
)
|
||||
saveStatusViewData(pachliAccountId, statusViewData.copy(translationState = TranslationState.SHOW_TRANSLATION))
|
||||
},
|
||||
{
|
||||
// Reset the translation state
|
||||
saveStatusViewData(pachliAccountId, statusViewData)
|
||||
},
|
||||
)
|
||||
return translation
|
||||
}
|
||||
|
||||
suspend fun translateUndo(statusViewData: StatusViewData) {
|
||||
saveStatusViewData(statusViewData.copy(translationState = TranslationState.SHOW_ORIGINAL))
|
||||
suspend fun translateUndo(pachliAccountId: Long, statusViewData: StatusViewData) {
|
||||
saveStatusViewData(pachliAccountId, statusViewData.copy(translationState = TranslationState.SHOW_ORIGINAL))
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
@ -649,8 +649,8 @@ class TimelineFragment :
|
||||
viewModel.accept(StatusAction.VoteInPoll(poll, choices, viewData))
|
||||
}
|
||||
|
||||
override fun clearWarningAction(viewData: StatusViewData) {
|
||||
viewModel.clearWarning(viewData)
|
||||
override fun clearWarningAction(pachliAccountId: Long, viewData: StatusViewData) {
|
||||
viewModel.clearWarning(pachliAccountId, viewData)
|
||||
}
|
||||
|
||||
override fun onEditFilterById(pachliAccountId: Long, filterId: String) {
|
||||
@ -668,12 +668,12 @@ class TimelineFragment :
|
||||
super.openReblog(status)
|
||||
}
|
||||
|
||||
override fun onExpandedChange(viewData: StatusViewData, expanded: Boolean) {
|
||||
viewModel.changeExpanded(expanded, viewData)
|
||||
override fun onExpandedChange(pachliAccountId: Long, viewData: StatusViewData, expanded: Boolean) {
|
||||
viewModel.changeExpanded(pachliAccountId, expanded, viewData)
|
||||
}
|
||||
|
||||
override fun onContentHiddenChange(viewData: StatusViewData, isShowing: Boolean) {
|
||||
viewModel.changeContentShowing(isShowing, viewData)
|
||||
override fun onContentHiddenChange(pachliAccountId: Long, viewData: StatusViewData, isShowing: Boolean) {
|
||||
viewModel.changeContentShowing(pachliAccountId, isShowing, viewData)
|
||||
}
|
||||
|
||||
override fun onShowReblogs(statusId: String) {
|
||||
@ -686,8 +686,8 @@ class TimelineFragment :
|
||||
activity?.startActivityWithDefaultTransition(intent)
|
||||
}
|
||||
|
||||
override fun onContentCollapsedChange(viewData: StatusViewData, isCollapsed: Boolean) {
|
||||
viewModel.changeContentCollapsed(isCollapsed, viewData)
|
||||
override fun onContentCollapsedChange(pachliAccountId: Long, viewData: StatusViewData, isCollapsed: Boolean) {
|
||||
viewModel.changeContentCollapsed(pachliAccountId, isCollapsed, viewData)
|
||||
}
|
||||
|
||||
// Can only translate the home timeline at the moment
|
||||
|
@ -41,10 +41,10 @@ class TimelinePagingAdapter(
|
||||
val inflater = LayoutInflater.from(viewGroup.context)
|
||||
return when (viewType) {
|
||||
VIEW_TYPE_STATUS_FILTERED -> {
|
||||
FilterableStatusViewHolder<StatusViewData>(pachliAccountId, ItemStatusWrapperBinding.inflate(inflater, viewGroup, false))
|
||||
FilterableStatusViewHolder<StatusViewData>(ItemStatusWrapperBinding.inflate(inflater, viewGroup, false))
|
||||
}
|
||||
VIEW_TYPE_STATUS -> {
|
||||
StatusViewHolder<StatusViewData>(pachliAccountId, ItemStatusBinding.inflate(inflater, viewGroup, false))
|
||||
StatusViewHolder<StatusViewData>(ItemStatusBinding.inflate(inflater, viewGroup, false))
|
||||
}
|
||||
else -> return object : RecyclerView.ViewHolder(inflater.inflate(R.layout.item_placeholder, viewGroup, false)) {}
|
||||
}
|
||||
@ -69,6 +69,7 @@ class TimelinePagingAdapter(
|
||||
) {
|
||||
getItem(position)?.let {
|
||||
(viewHolder as StatusViewHolder<StatusViewData>).setupWithStatus(
|
||||
pachliAccountId,
|
||||
it,
|
||||
statusListener,
|
||||
statusDisplayOptions,
|
||||
|
@ -110,39 +110,39 @@ class CachedTimelineViewModel @Inject constructor(
|
||||
// handled by CacheUpdater
|
||||
}
|
||||
|
||||
override fun changeExpanded(expanded: Boolean, status: StatusViewData) {
|
||||
override fun changeExpanded(pachliAccountId: Long, expanded: Boolean, status: StatusViewData) {
|
||||
viewModelScope.launch {
|
||||
repository.saveStatusViewData(status.copy(isExpanded = expanded))
|
||||
repository.saveStatusViewData(pachliAccountId, status.copy(isExpanded = expanded))
|
||||
}
|
||||
}
|
||||
|
||||
override fun changeContentShowing(isShowing: Boolean, status: StatusViewData) {
|
||||
override fun changeContentShowing(pachliAccountId: Long, isShowing: Boolean, status: StatusViewData) {
|
||||
viewModelScope.launch {
|
||||
repository.saveStatusViewData(status.copy(isShowingContent = isShowing))
|
||||
repository.saveStatusViewData(pachliAccountId, status.copy(isShowingContent = isShowing))
|
||||
}
|
||||
}
|
||||
|
||||
override fun changeContentCollapsed(isCollapsed: Boolean, status: StatusViewData) {
|
||||
override fun changeContentCollapsed(pachliAccountId: Long, isCollapsed: Boolean, status: StatusViewData) {
|
||||
viewModelScope.launch {
|
||||
repository.saveStatusViewData(status.copy(isCollapsed = isCollapsed))
|
||||
repository.saveStatusViewData(pachliAccountId, status.copy(isCollapsed = isCollapsed))
|
||||
}
|
||||
}
|
||||
|
||||
override fun removeAllByAccountId(accountId: String) {
|
||||
override fun removeAllByAccountId(pachliAccountId: Long, accountId: String) {
|
||||
viewModelScope.launch {
|
||||
repository.removeAllByAccountId(accountId)
|
||||
repository.removeAllByAccountId(pachliAccountId, accountId)
|
||||
}
|
||||
}
|
||||
|
||||
override fun removeAllByInstance(instance: String) {
|
||||
override fun removeAllByInstance(pachliAccountId: Long, instance: String) {
|
||||
viewModelScope.launch {
|
||||
repository.removeAllByInstance(instance)
|
||||
repository.removeAllByInstance(pachliAccountId, instance)
|
||||
}
|
||||
}
|
||||
|
||||
override fun clearWarning(statusViewData: StatusViewData) {
|
||||
override fun clearWarning(pachliAccountId: Long, statusViewData: StatusViewData) {
|
||||
viewModelScope.launch {
|
||||
repository.clearStatusWarning(statusViewData.actionableId)
|
||||
repository.clearStatusWarning(pachliAccountId, statusViewData.actionableId)
|
||||
}
|
||||
}
|
||||
|
||||
@ -166,21 +166,21 @@ class CachedTimelineViewModel @Inject constructor(
|
||||
// handled by CacheUpdater
|
||||
}
|
||||
|
||||
override fun reloadKeepingReadingPosition() {
|
||||
super.reloadKeepingReadingPosition()
|
||||
override fun reloadKeepingReadingPosition(pachliAccountId: Long) {
|
||||
super.reloadKeepingReadingPosition(pachliAccountId)
|
||||
viewModelScope.launch {
|
||||
repository.clearAndReload()
|
||||
repository.clearAndReload(pachliAccountId)
|
||||
}
|
||||
}
|
||||
|
||||
override fun reloadFromNewest() {
|
||||
super.reloadFromNewest()
|
||||
override fun reloadFromNewest(pachliAccountId: Long) {
|
||||
super.reloadFromNewest(pachliAccountId)
|
||||
viewModelScope.launch {
|
||||
repository.clearAndReloadFromNewest()
|
||||
repository.clearAndReloadFromNewest(pachliAccountId)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun invalidate() {
|
||||
repository.invalidate()
|
||||
override suspend fun invalidate(pachliAccountId: Long) {
|
||||
repository.invalidate(pachliAccountId)
|
||||
}
|
||||
}
|
||||
|
@ -111,21 +111,21 @@ class NetworkTimelineViewModel @Inject constructor(
|
||||
repository.invalidate()
|
||||
}
|
||||
|
||||
override fun changeExpanded(expanded: Boolean, status: StatusViewData) {
|
||||
override fun changeExpanded(pachliAccountId: Long, expanded: Boolean, status: StatusViewData) {
|
||||
modifiedViewData[status.id] = status.copy(
|
||||
isExpanded = expanded,
|
||||
)
|
||||
repository.invalidate()
|
||||
}
|
||||
|
||||
override fun changeContentShowing(isShowing: Boolean, status: StatusViewData) {
|
||||
override fun changeContentShowing(pachliAccountId: Long, isShowing: Boolean, status: StatusViewData) {
|
||||
modifiedViewData[status.id] = status.copy(
|
||||
isShowingContent = isShowing,
|
||||
)
|
||||
repository.invalidate()
|
||||
}
|
||||
|
||||
override fun changeContentCollapsed(isCollapsed: Boolean, status: StatusViewData) {
|
||||
override fun changeContentCollapsed(pachliAccountId: Long, isCollapsed: Boolean, status: StatusViewData) {
|
||||
Timber.d("changeContentCollapsed: %s", isCollapsed)
|
||||
Timber.d(" %s", status.content)
|
||||
modifiedViewData[status.id] = status.copy(
|
||||
@ -134,13 +134,13 @@ class NetworkTimelineViewModel @Inject constructor(
|
||||
repository.invalidate()
|
||||
}
|
||||
|
||||
override fun removeAllByAccountId(accountId: String) {
|
||||
override fun removeAllByAccountId(pachliAccountId: Long, accountId: String) {
|
||||
viewModelScope.launch {
|
||||
repository.removeAllByAccountId(accountId)
|
||||
}
|
||||
}
|
||||
|
||||
override fun removeAllByInstance(instance: String) {
|
||||
override fun removeAllByInstance(pachliAccountId: Long, instance: String) {
|
||||
viewModelScope.launch {
|
||||
repository.removeAllByInstance(instance)
|
||||
}
|
||||
@ -187,19 +187,19 @@ class NetworkTimelineViewModel @Inject constructor(
|
||||
repository.invalidate()
|
||||
}
|
||||
|
||||
override fun reloadKeepingReadingPosition() {
|
||||
super.reloadKeepingReadingPosition()
|
||||
override fun reloadKeepingReadingPosition(pachliAccountId: Long) {
|
||||
super.reloadKeepingReadingPosition(pachliAccountId)
|
||||
viewModelScope.launch {
|
||||
repository.reload()
|
||||
}
|
||||
}
|
||||
|
||||
override fun reloadFromNewest() {
|
||||
super.reloadFromNewest()
|
||||
reloadKeepingReadingPosition()
|
||||
override fun reloadFromNewest(pachliAccountId: Long) {
|
||||
super.reloadFromNewest(pachliAccountId)
|
||||
reloadKeepingReadingPosition(pachliAccountId)
|
||||
}
|
||||
|
||||
override fun clearWarning(statusViewData: StatusViewData) {
|
||||
override fun clearWarning(pachliAccountId: Long, statusViewData: StatusViewData) {
|
||||
viewModelScope.launch {
|
||||
repository.updateActionableStatusById(statusViewData.actionableId) {
|
||||
it.copy(filtered = null)
|
||||
@ -207,7 +207,7 @@ class NetworkTimelineViewModel @Inject constructor(
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun invalidate() {
|
||||
override suspend fun invalidate(pachliAccountId: Long) {
|
||||
repository.invalidate()
|
||||
}
|
||||
}
|
||||
|
@ -150,6 +150,8 @@ sealed interface UiSuccess {
|
||||
|
||||
/** Actions the user can trigger on an individual status */
|
||||
sealed interface StatusAction : FallibleUiAction {
|
||||
// TODO: Include a property for the PachliAccountId the action is being performed as.
|
||||
|
||||
val statusViewData: StatusViewData
|
||||
|
||||
/** Set the bookmark state for a status */
|
||||
@ -342,7 +344,7 @@ abstract class TimelineViewModel(
|
||||
else -> null
|
||||
}
|
||||
if (reload) {
|
||||
reloadKeepingReadingPosition()
|
||||
reloadKeepingReadingPosition(activeAccount.id)
|
||||
}
|
||||
}.onFailure {
|
||||
_uiErrorChannel.send(UiError.GetFilters(RuntimeException(it.fmt(context))))
|
||||
@ -381,7 +383,7 @@ abstract class TimelineViewModel(
|
||||
action.choices,
|
||||
)
|
||||
is StatusAction.Translate -> {
|
||||
timelineCases.translate(action.statusViewData)
|
||||
timelineCases.translate(activeAccount.id, action.statusViewData)
|
||||
}
|
||||
}.getOrThrow()
|
||||
uiSuccess.emit(StatusActionSuccess.from(action))
|
||||
@ -468,14 +470,14 @@ abstract class TimelineViewModel(
|
||||
accountManager.saveAccount(activeAccount)
|
||||
}
|
||||
Timber.d("Reload because InfallibleUiAction.LoadNewest")
|
||||
reloadFromNewest()
|
||||
reloadFromNewest(activeAccount.id)
|
||||
}
|
||||
}
|
||||
|
||||
// Undo status translations
|
||||
viewModelScope.launch {
|
||||
uiAction.filterIsInstance<InfallibleUiAction.TranslateUndo>().collectLatest {
|
||||
timelineCases.translateUndo(it.statusViewData)
|
||||
timelineCases.translateUndo(activeAccount.id, it.statusViewData)
|
||||
}
|
||||
}
|
||||
|
||||
@ -495,15 +497,15 @@ abstract class TimelineViewModel(
|
||||
|
||||
abstract fun updatePoll(newPoll: Poll, status: StatusViewData)
|
||||
|
||||
abstract fun changeExpanded(expanded: Boolean, status: StatusViewData)
|
||||
abstract fun changeExpanded(pachliAccountId: Long, expanded: Boolean, status: StatusViewData)
|
||||
|
||||
abstract fun changeContentShowing(isShowing: Boolean, status: StatusViewData)
|
||||
abstract fun changeContentShowing(pachliAccountId: Long, isShowing: Boolean, status: StatusViewData)
|
||||
|
||||
abstract fun changeContentCollapsed(isCollapsed: Boolean, status: StatusViewData)
|
||||
abstract fun changeContentCollapsed(pachliAccountId: Long, isCollapsed: Boolean, status: StatusViewData)
|
||||
|
||||
abstract fun removeAllByAccountId(accountId: String)
|
||||
abstract fun removeAllByAccountId(pachliAccountId: Long, accountId: String)
|
||||
|
||||
abstract fun removeAllByInstance(instance: String)
|
||||
abstract fun removeAllByInstance(pachliAccountId: Long, instance: String)
|
||||
|
||||
abstract fun removeStatusWithId(id: String)
|
||||
|
||||
@ -521,7 +523,7 @@ abstract class TimelineViewModel(
|
||||
* Subclasses should call this, then start loading data.
|
||||
*/
|
||||
@CallSuper
|
||||
open fun reloadKeepingReadingPosition() {
|
||||
open fun reloadKeepingReadingPosition(pachliAccountId: Long) {
|
||||
reload.getAndUpdate { it + 1 }
|
||||
}
|
||||
|
||||
@ -531,14 +533,14 @@ abstract class TimelineViewModel(
|
||||
* Subclasses should call this, then start loading data.
|
||||
*/
|
||||
@CallSuper
|
||||
open fun reloadFromNewest() {
|
||||
open fun reloadFromNewest(pachliAccountId: Long) {
|
||||
reload.getAndUpdate { it + 1 }
|
||||
}
|
||||
|
||||
abstract fun clearWarning(statusViewData: StatusViewData)
|
||||
abstract fun clearWarning(pachliAccountId: Long, statusViewData: StatusViewData)
|
||||
|
||||
/** Triggered when currently displayed data must be reloaded. */
|
||||
protected abstract suspend fun invalidate()
|
||||
protected abstract suspend fun invalidate(pachliAccountId: Long)
|
||||
|
||||
protected fun shouldFilterStatus(statusViewData: StatusViewData): FilterAction {
|
||||
val status = statusViewData.status
|
||||
@ -564,7 +566,7 @@ abstract class TimelineViewModel(
|
||||
filterRemoveReplies = timeline is Timeline.Home && !filter
|
||||
if (oldRemoveReplies != filterRemoveReplies) {
|
||||
Timber.d("Reload because TAB_FILTER_HOME_REPLIES changed")
|
||||
reloadKeepingReadingPosition()
|
||||
reloadKeepingReadingPosition(activeAccount.id)
|
||||
}
|
||||
}
|
||||
PrefKeys.TAB_FILTER_HOME_BOOSTS -> {
|
||||
@ -573,7 +575,7 @@ abstract class TimelineViewModel(
|
||||
filterRemoveReblogs = timeline is Timeline.Home && !filter
|
||||
if (oldRemoveReblogs != filterRemoveReblogs) {
|
||||
Timber.d("Reload because TAB_FILTER_HOME_BOOSTS changed")
|
||||
reloadKeepingReadingPosition()
|
||||
reloadKeepingReadingPosition(activeAccount.id)
|
||||
}
|
||||
}
|
||||
PrefKeys.TAB_SHOW_HOME_SELF_BOOSTS -> {
|
||||
@ -582,7 +584,7 @@ abstract class TimelineViewModel(
|
||||
filterRemoveSelfReblogs = timeline is Timeline.Home && !filter
|
||||
if (oldRemoveSelfReblogs != filterRemoveSelfReblogs) {
|
||||
Timber.d("Reload because TAB_SHOW_SOME_SELF_BOOSTS changed")
|
||||
reloadKeepingReadingPosition()
|
||||
reloadKeepingReadingPosition(activeAccount.id)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -596,30 +598,30 @@ abstract class TimelineViewModel(
|
||||
is PinEvent -> handlePinEvent(event)
|
||||
is MuteConversationEvent -> {
|
||||
Timber.d("Reload because MuteConversationEvent")
|
||||
reloadKeepingReadingPosition()
|
||||
reloadKeepingReadingPosition(activeAccount.id)
|
||||
}
|
||||
is UnfollowEvent -> {
|
||||
if (timeline is Timeline.Home) {
|
||||
val id = event.accountId
|
||||
removeAllByAccountId(id)
|
||||
removeAllByAccountId(activeAccount.id, id)
|
||||
}
|
||||
}
|
||||
is BlockEvent -> {
|
||||
if (timeline !is Timeline.User) {
|
||||
val id = event.accountId
|
||||
removeAllByAccountId(id)
|
||||
removeAllByAccountId(activeAccount.id, id)
|
||||
}
|
||||
}
|
||||
is MuteEvent -> {
|
||||
if (timeline !is Timeline.User) {
|
||||
val id = event.accountId
|
||||
removeAllByAccountId(id)
|
||||
removeAllByAccountId(activeAccount.id, id)
|
||||
}
|
||||
}
|
||||
is DomainMuteEvent -> {
|
||||
if (timeline !is Timeline.User) {
|
||||
val instance = event.instance
|
||||
removeAllByInstance(instance)
|
||||
removeAllByInstance(activeAccount.id, instance)
|
||||
}
|
||||
}
|
||||
is StatusDeletedEvent -> {
|
||||
|
@ -42,13 +42,13 @@ class ThreadAdapter(
|
||||
val inflater = LayoutInflater.from(parent.context)
|
||||
return when (viewType) {
|
||||
VIEW_TYPE_STATUS -> {
|
||||
StatusViewHolder(pachliAccountId, ItemStatusBinding.inflate(inflater, parent, false))
|
||||
StatusViewHolder(ItemStatusBinding.inflate(inflater, parent, false))
|
||||
}
|
||||
VIEW_TYPE_STATUS_FILTERED -> {
|
||||
FilterableStatusViewHolder(pachliAccountId, ItemStatusWrapperBinding.inflate(inflater, parent, false))
|
||||
FilterableStatusViewHolder(ItemStatusWrapperBinding.inflate(inflater, parent, false))
|
||||
}
|
||||
VIEW_TYPE_STATUS_DETAILED -> {
|
||||
StatusDetailedViewHolder(pachliAccountId, ItemStatusDetailedBinding.inflate(inflater, parent, false))
|
||||
StatusDetailedViewHolder(ItemStatusDetailedBinding.inflate(inflater, parent, false))
|
||||
}
|
||||
else -> error("Unknown item type: $viewType")
|
||||
}
|
||||
@ -56,7 +56,7 @@ class ThreadAdapter(
|
||||
|
||||
override fun onBindViewHolder(viewHolder: StatusBaseViewHolder<StatusViewData>, position: Int) {
|
||||
val status = getItem(position)
|
||||
viewHolder.setupWithStatus(status, statusActionListener, statusDisplayOptions)
|
||||
viewHolder.setupWithStatus(pachliAccountId, status, statusActionListener, statusDisplayOptions)
|
||||
}
|
||||
|
||||
override fun getItemViewType(position: Int): Int {
|
||||
|
@ -339,11 +339,11 @@ class ViewThreadFragment :
|
||||
)
|
||||
}
|
||||
|
||||
override fun onExpandedChange(viewData: StatusViewData, expanded: Boolean) {
|
||||
override fun onExpandedChange(pachliAccountId: Long, viewData: StatusViewData, expanded: Boolean) {
|
||||
viewModel.changeExpanded(expanded, viewData)
|
||||
}
|
||||
|
||||
override fun onContentHiddenChange(viewData: StatusViewData, isShowing: Boolean) {
|
||||
override fun onContentHiddenChange(pachliAccountId: Long, viewData: StatusViewData, isShowing: Boolean) {
|
||||
viewModel.changeContentShowing(isShowing, viewData)
|
||||
}
|
||||
|
||||
@ -357,7 +357,7 @@ class ViewThreadFragment :
|
||||
activity?.startActivityWithDefaultTransition(intent)
|
||||
}
|
||||
|
||||
override fun onContentCollapsedChange(viewData: StatusViewData, isCollapsed: Boolean) {
|
||||
override fun onContentCollapsedChange(pachliAccountId: Long, viewData: StatusViewData, isCollapsed: Boolean) {
|
||||
viewModel.changeContentCollapsed(isCollapsed, viewData)
|
||||
}
|
||||
|
||||
@ -397,7 +397,7 @@ class ViewThreadFragment :
|
||||
}
|
||||
}
|
||||
|
||||
override fun clearWarningAction(viewData: StatusViewData) {
|
||||
override fun clearWarningAction(pachliAccountId: Long, viewData: StatusViewData) {
|
||||
viewModel.clearWarning(viewData)
|
||||
}
|
||||
|
||||
|
@ -201,49 +201,52 @@ class ViewThreadViewModel @Inject constructor(
|
||||
|
||||
val contextResult = contextCall.await()
|
||||
|
||||
contextResult.fold({ statusContext ->
|
||||
val ids = statusContext.ancestors.map { it.id } + statusContext.descendants.map { it.id }
|
||||
val cachedViewData = repository.getStatusViewData(ids)
|
||||
val cachedTranslations = repository.getStatusTranslations(ids)
|
||||
val ancestors = statusContext.ancestors.map { status ->
|
||||
val svd = cachedViewData[status.id]
|
||||
StatusViewData.from(
|
||||
status,
|
||||
isShowingContent = svd?.contentShowing ?: (alwaysShowSensitiveMedia || !status.actionableStatus.sensitive),
|
||||
isExpanded = svd?.expanded ?: alwaysOpenSpoiler,
|
||||
isCollapsed = svd?.contentCollapsed ?: true,
|
||||
isDetailed = false,
|
||||
translationState = svd?.translationState ?: TranslationState.SHOW_ORIGINAL,
|
||||
translation = cachedTranslations[status.id],
|
||||
)
|
||||
}.filterByFilterAction()
|
||||
val descendants = statusContext.descendants.map { status ->
|
||||
val svd = cachedViewData[status.id]
|
||||
StatusViewData.from(
|
||||
status,
|
||||
isShowingContent = svd?.contentShowing ?: (alwaysShowSensitiveMedia || !status.actionableStatus.sensitive),
|
||||
isExpanded = svd?.expanded ?: alwaysOpenSpoiler,
|
||||
isCollapsed = svd?.contentCollapsed ?: true,
|
||||
isDetailed = false,
|
||||
translationState = svd?.translationState ?: TranslationState.SHOW_ORIGINAL,
|
||||
translation = cachedTranslations[status.id],
|
||||
)
|
||||
}.filterByFilterAction()
|
||||
val statuses = ancestors + detailedStatus + descendants
|
||||
contextResult.fold(
|
||||
{ statusContext ->
|
||||
val ids = statusContext.ancestors.map { it.id } + statusContext.descendants.map { it.id }
|
||||
val cachedViewData = repository.getStatusViewData(activeAccount.id, ids)
|
||||
val cachedTranslations = repository.getStatusTranslations(activeAccount.id, ids)
|
||||
val ancestors = statusContext.ancestors.map { status ->
|
||||
val svd = cachedViewData[status.id]
|
||||
StatusViewData.from(
|
||||
status,
|
||||
isShowingContent = svd?.contentShowing ?: (alwaysShowSensitiveMedia || !status.actionableStatus.sensitive),
|
||||
isExpanded = svd?.expanded ?: alwaysOpenSpoiler,
|
||||
isCollapsed = svd?.contentCollapsed ?: true,
|
||||
isDetailed = false,
|
||||
translationState = svd?.translationState ?: TranslationState.SHOW_ORIGINAL,
|
||||
translation = cachedTranslations[status.id],
|
||||
)
|
||||
}.filterByFilterAction()
|
||||
val descendants = statusContext.descendants.map { status ->
|
||||
val svd = cachedViewData[status.id]
|
||||
StatusViewData.from(
|
||||
status,
|
||||
isShowingContent = svd?.contentShowing ?: (alwaysShowSensitiveMedia || !status.actionableStatus.sensitive),
|
||||
isExpanded = svd?.expanded ?: alwaysOpenSpoiler,
|
||||
isCollapsed = svd?.contentCollapsed ?: true,
|
||||
isDetailed = false,
|
||||
translationState = svd?.translationState ?: TranslationState.SHOW_ORIGINAL,
|
||||
translation = cachedTranslations[status.id],
|
||||
)
|
||||
}.filterByFilterAction()
|
||||
val statuses = ancestors + detailedStatus + descendants
|
||||
|
||||
_uiState.value = ThreadUiState.Success(
|
||||
statusViewData = statuses,
|
||||
detailedStatusPosition = ancestors.size,
|
||||
revealButton = statuses.getRevealButtonState(),
|
||||
)
|
||||
}, { throwable ->
|
||||
_errors.emit(throwable)
|
||||
_uiState.value = ThreadUiState.Success(
|
||||
statusViewData = listOf(detailedStatus),
|
||||
detailedStatusPosition = 0,
|
||||
revealButton = RevealButtonState.NO_BUTTON,
|
||||
)
|
||||
})
|
||||
_uiState.value = ThreadUiState.Success(
|
||||
statusViewData = statuses,
|
||||
detailedStatusPosition = ancestors.size,
|
||||
revealButton = statuses.getRevealButtonState(),
|
||||
)
|
||||
},
|
||||
{ throwable ->
|
||||
_errors.emit(throwable)
|
||||
_uiState.value = ThreadUiState.Success(
|
||||
statusViewData = listOf(detailedStatus),
|
||||
detailedStatusPosition = 0,
|
||||
revealButton = RevealButtonState.NO_BUTTON,
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@ -335,7 +338,7 @@ class ViewThreadViewModel @Inject constructor(
|
||||
)
|
||||
}
|
||||
viewModelScope.launch {
|
||||
repository.saveStatusViewData(status.copy(isExpanded = expanded))
|
||||
repository.saveStatusViewData(activeAccount.id, status.copy(isExpanded = expanded))
|
||||
}
|
||||
}
|
||||
|
||||
@ -344,7 +347,7 @@ class ViewThreadViewModel @Inject constructor(
|
||||
viewData.copy(isShowingContent = isShowing)
|
||||
}
|
||||
viewModelScope.launch {
|
||||
repository.saveStatusViewData(status.copy(isShowingContent = isShowing))
|
||||
repository.saveStatusViewData(activeAccount.id, status.copy(isShowingContent = isShowing))
|
||||
}
|
||||
}
|
||||
|
||||
@ -353,7 +356,7 @@ class ViewThreadViewModel @Inject constructor(
|
||||
viewData.copy(isCollapsed = isCollapsed)
|
||||
}
|
||||
viewModelScope.launch {
|
||||
repository.saveStatusViewData(status.copy(isCollapsed = isCollapsed))
|
||||
repository.saveStatusViewData(activeAccount.id, status.copy(isCollapsed = isCollapsed))
|
||||
}
|
||||
}
|
||||
|
||||
@ -455,28 +458,31 @@ class ViewThreadViewModel @Inject constructor(
|
||||
|
||||
fun translate(statusViewData: StatusViewData) {
|
||||
viewModelScope.launch {
|
||||
repository.translate(statusViewData).fold({
|
||||
val translatedEntity = TranslatedStatusEntity(
|
||||
serverId = statusViewData.actionableId,
|
||||
timelineUserId = activeAccount.id,
|
||||
content = it.content,
|
||||
spoilerText = it.spoilerText,
|
||||
poll = it.poll,
|
||||
attachments = it.attachments,
|
||||
provider = it.provider,
|
||||
)
|
||||
updateStatusViewData(statusViewData.status.id) { viewData ->
|
||||
viewData.copy(translation = translatedEntity, translationState = TranslationState.SHOW_TRANSLATION)
|
||||
}
|
||||
}, {
|
||||
// Mastodon returns 403 if it thinks the original status language is the
|
||||
// same as the user's language, ignoring the actual content of the status
|
||||
// (https://github.com/mastodon/documentation/issues/1330). Nothing useful
|
||||
// to do here so swallow the error
|
||||
if (it is HttpException && it.code() == 403) return@fold
|
||||
repository.translate(activeAccount.id, statusViewData).fold(
|
||||
{
|
||||
val translatedEntity = TranslatedStatusEntity(
|
||||
serverId = statusViewData.actionableId,
|
||||
timelineUserId = activeAccount.id,
|
||||
content = it.content,
|
||||
spoilerText = it.spoilerText,
|
||||
poll = it.poll,
|
||||
attachments = it.attachments,
|
||||
provider = it.provider,
|
||||
)
|
||||
updateStatusViewData(statusViewData.status.id) { viewData ->
|
||||
viewData.copy(translation = translatedEntity, translationState = TranslationState.SHOW_TRANSLATION)
|
||||
}
|
||||
},
|
||||
{
|
||||
// Mastodon returns 403 if it thinks the original status language is the
|
||||
// same as the user's language, ignoring the actual content of the status
|
||||
// (https://github.com/mastodon/documentation/issues/1330). Nothing useful
|
||||
// to do here so swallow the error
|
||||
if (it is HttpException && it.code() == 403) return@fold
|
||||
|
||||
_errors.emit(it)
|
||||
})
|
||||
_errors.emit(it)
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@ -486,6 +492,7 @@ class ViewThreadViewModel @Inject constructor(
|
||||
}
|
||||
viewModelScope.launch {
|
||||
repository.saveStatusViewData(
|
||||
activeAccount.id,
|
||||
statusViewData.copy(translationState = TranslationState.SHOW_ORIGINAL),
|
||||
)
|
||||
}
|
||||
|
@ -36,8 +36,8 @@ interface StatusActionListener<T : IStatusViewData> : LinkListener {
|
||||
* Open reblog author for the status.
|
||||
*/
|
||||
fun onOpenReblog(status: Status)
|
||||
fun onExpandedChange(viewData: T, expanded: Boolean)
|
||||
fun onContentHiddenChange(viewData: T, isShowing: Boolean)
|
||||
fun onExpandedChange(pachliAccountId: Long, viewData: T, expanded: Boolean)
|
||||
fun onContentHiddenChange(pachliAccountId: Long, viewData: T, isShowing: Boolean)
|
||||
|
||||
/**
|
||||
* Called when the status [android.widget.ToggleButton] responsible for collapsing long
|
||||
@ -45,7 +45,7 @@ interface StatusActionListener<T : IStatusViewData> : LinkListener {
|
||||
*
|
||||
* @param isCollapsed Whether the status content is shown in a collapsed state or fully.
|
||||
*/
|
||||
fun onContentCollapsedChange(viewData: T, isCollapsed: Boolean)
|
||||
fun onContentCollapsedChange(pachliAccountId: Long, viewData: T, isCollapsed: Boolean)
|
||||
|
||||
/**
|
||||
* called when the reblog count has been clicked
|
||||
@ -58,7 +58,7 @@ interface StatusActionListener<T : IStatusViewData> : LinkListener {
|
||||
fun onShowFavs(statusId: String) {}
|
||||
fun onVoteInPoll(viewData: T, poll: Poll, choices: List<Int>)
|
||||
fun onShowEdits(statusId: String) {}
|
||||
fun clearWarningAction(viewData: T)
|
||||
fun clearWarningAction(pachliAccountId: Long, viewData: T)
|
||||
|
||||
/** Edit the filter that matched this status. */
|
||||
fun onEditFilterById(pachliAccountId: Long, filterId: String)
|
||||
|
@ -143,11 +143,11 @@ class TimelineCases @Inject constructor(
|
||||
return mastodonApi.rejectFollowRequest(accountId)
|
||||
}
|
||||
|
||||
suspend fun translate(statusViewData: StatusViewData): NetworkResult<Translation> {
|
||||
return cachedTimelineRepository.translate(statusViewData)
|
||||
suspend fun translate(pachliAccountId: Long, statusViewData: StatusViewData): NetworkResult<Translation> {
|
||||
return cachedTimelineRepository.translate(pachliAccountId, statusViewData)
|
||||
}
|
||||
|
||||
suspend fun translateUndo(statusViewData: StatusViewData) {
|
||||
cachedTimelineRepository.translateUndo(statusViewData)
|
||||
suspend fun translateUndo(pachliAccountId: Long, statusViewData: StatusViewData) {
|
||||
cachedTimelineRepository.translateUndo(pachliAccountId, statusViewData)
|
||||
}
|
||||
}
|
||||
|
@ -165,7 +165,7 @@ class ListStatusAccessibilityDelegate<T : IStatusViewData>(
|
||||
forceFocus(host)
|
||||
}
|
||||
app.pachli.core.ui.R.id.action_collapse_cw -> {
|
||||
statusActionListener.onExpandedChange(status, false)
|
||||
statusActionListener.onExpandedChange(pachliAccountId, status, false)
|
||||
interrupt()
|
||||
}
|
||||
app.pachli.core.ui.R.id.action_links -> showLinksDialog(host)
|
||||
@ -192,7 +192,7 @@ class ListStatusAccessibilityDelegate<T : IStatusViewData>(
|
||||
app.pachli.core.ui.R.id.action_more -> {
|
||||
statusActionListener.onMore(host, status)
|
||||
}
|
||||
app.pachli.core.ui.R.id.action_show_anyway -> statusActionListener.clearWarningAction(status)
|
||||
app.pachli.core.ui.R.id.action_show_anyway -> statusActionListener.clearWarningAction(pachliAccountId, status)
|
||||
app.pachli.core.ui.R.id.action_edit_filter -> {
|
||||
(recyclerView.findContainingViewHolder(host) as? FilterableStatusViewHolder<*>)?.matchedFilter?.let {
|
||||
statusActionListener.onEditFilterById(pachliAccountId, it.id)
|
||||
|
@ -46,6 +46,7 @@ import org.junit.Before
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.mockito.ArgumentMatchers.anyLong
|
||||
import org.mockito.kotlin.any
|
||||
import org.mockito.kotlin.doReturn
|
||||
import org.mockito.kotlin.mock
|
||||
@ -183,8 +184,8 @@ class ViewThreadViewModelTest {
|
||||
)
|
||||
|
||||
val cachedTimelineRepository: CachedTimelineRepository = mock {
|
||||
onBlocking { getStatusViewData(any()) } doReturn emptyMap()
|
||||
onBlocking { getStatusTranslations(any()) } doReturn emptyMap()
|
||||
onBlocking { getStatusViewData(anyLong(), any()) } doReturn emptyMap()
|
||||
onBlocking { getStatusTranslations(anyLong(), any()) } doReturn emptyMap()
|
||||
}
|
||||
|
||||
viewModel = ViewThreadViewModel(
|
||||
|
Loading…
x
Reference in New Issue
Block a user