use ViewData only instead of Pair<Status, ViewData> in Search (#2336)
This commit is contained in:
parent
c592dfef78
commit
2960a85ff1
3 changed files with 68 additions and 80 deletions
|
@ -53,17 +53,15 @@ class SearchViewModel @Inject constructor(
|
|||
val alwaysShowSensitiveMedia = activeAccount?.alwaysShowSensitiveMedia ?: false
|
||||
val alwaysOpenSpoiler = activeAccount?.alwaysOpenSpoiler ?: false
|
||||
|
||||
private val loadedStatuses: MutableList<Pair<Status, StatusViewData.Concrete>> = mutableListOf()
|
||||
private val loadedStatuses: MutableList<StatusViewData.Concrete> = mutableListOf()
|
||||
|
||||
private val statusesPagingSourceFactory = SearchPagingSourceFactory(mastodonApi, SearchType.Status, loadedStatuses) {
|
||||
it.statuses.map { status ->
|
||||
val statusViewData = status.toViewData(
|
||||
status.toViewData(
|
||||
isShowingContent = alwaysShowSensitiveMedia || !status.actionableStatus.sensitive,
|
||||
isExpanded = alwaysOpenSpoiler,
|
||||
isCollapsed = true
|
||||
)
|
||||
|
||||
Pair(status, statusViewData)
|
||||
}.apply {
|
||||
loadedStatuses.addAll(this)
|
||||
}
|
||||
|
@ -100,11 +98,11 @@ class SearchViewModel @Inject constructor(
|
|||
hashtagsPagingSourceFactory.newSearch(query)
|
||||
}
|
||||
|
||||
fun removeItem(status: Pair<Status, StatusViewData.Concrete>) {
|
||||
timelineCases.delete(status.first.id)
|
||||
fun removeItem(statusViewData: StatusViewData.Concrete) {
|
||||
timelineCases.delete(statusViewData.id)
|
||||
.subscribe(
|
||||
{
|
||||
if (loadedStatuses.remove(status))
|
||||
if (loadedStatuses.remove(statusViewData))
|
||||
statusesPagingSourceFactory.invalidate()
|
||||
},
|
||||
{ err ->
|
||||
|
@ -114,82 +112,81 @@ class SearchViewModel @Inject constructor(
|
|||
.autoDispose()
|
||||
}
|
||||
|
||||
fun expandedChange(status: Pair<Status, StatusViewData.Concrete>, expanded: Boolean) {
|
||||
val idx = loadedStatuses.indexOf(status)
|
||||
fun expandedChange(statusViewData: StatusViewData.Concrete, expanded: Boolean) {
|
||||
val idx = loadedStatuses.indexOf(statusViewData)
|
||||
if (idx >= 0) {
|
||||
loadedStatuses[idx] = Pair(status.first, status.second.copy(isExpanded = expanded))
|
||||
loadedStatuses[idx] = statusViewData.copy(isExpanded = expanded)
|
||||
statusesPagingSourceFactory.invalidate()
|
||||
}
|
||||
}
|
||||
|
||||
fun reblog(status: Pair<Status, StatusViewData.Concrete>, reblog: Boolean) {
|
||||
timelineCases.reblog(status.first.id, reblog)
|
||||
fun reblog(statusViewData: StatusViewData.Concrete, reblog: Boolean) {
|
||||
timelineCases.reblog(statusViewData.id, reblog)
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(
|
||||
{ setRebloggedForStatus(status, reblog) },
|
||||
{ t -> Log.d(TAG, "Failed to reblog status ${status.first.id}", t) }
|
||||
{ setRebloggedForStatus(statusViewData, reblog) },
|
||||
{ t -> Log.d(TAG, "Failed to reblog status ${statusViewData.id}", t) }
|
||||
)
|
||||
.autoDispose()
|
||||
}
|
||||
|
||||
private fun setRebloggedForStatus(status: Pair<Status, StatusViewData.Concrete>, reblog: Boolean) {
|
||||
status.first.reblogged = reblog
|
||||
status.first.reblog?.reblogged = reblog
|
||||
private fun setRebloggedForStatus(statusViewData: StatusViewData.Concrete, reblog: Boolean) {
|
||||
statusViewData.status.reblogged = reblog
|
||||
statusViewData.status.reblog?.reblogged = reblog
|
||||
statusesPagingSourceFactory.invalidate()
|
||||
}
|
||||
|
||||
fun contentHiddenChange(status: Pair<Status, StatusViewData.Concrete>, isShowing: Boolean) {
|
||||
val idx = loadedStatuses.indexOf(status)
|
||||
fun contentHiddenChange(statusViewData: StatusViewData.Concrete, isShowing: Boolean) {
|
||||
val idx = loadedStatuses.indexOf(statusViewData)
|
||||
if (idx >= 0) {
|
||||
loadedStatuses[idx] = Pair(status.first, status.second.copy(isShowingContent = isShowing))
|
||||
loadedStatuses[idx] = statusViewData.copy(isShowingContent = isShowing)
|
||||
statusesPagingSourceFactory.invalidate()
|
||||
}
|
||||
}
|
||||
|
||||
fun collapsedChange(status: Pair<Status, StatusViewData.Concrete>, collapsed: Boolean) {
|
||||
val idx = loadedStatuses.indexOf(status)
|
||||
fun collapsedChange(statusViewData: StatusViewData.Concrete, collapsed: Boolean) {
|
||||
val idx = loadedStatuses.indexOf(statusViewData)
|
||||
if (idx >= 0) {
|
||||
loadedStatuses[idx] = Pair(status.first, status.second.copy(isCollapsed = collapsed))
|
||||
loadedStatuses[idx] = statusViewData.copy(isCollapsed = collapsed)
|
||||
statusesPagingSourceFactory.invalidate()
|
||||
}
|
||||
}
|
||||
|
||||
fun voteInPoll(status: Pair<Status, StatusViewData.Concrete>, choices: MutableList<Int>) {
|
||||
val votedPoll = status.first.actionableStatus.poll!!.votedCopy(choices)
|
||||
updateStatus(status, votedPoll)
|
||||
timelineCases.voteInPoll(status.first.id, votedPoll.id, choices)
|
||||
fun voteInPoll(statusViewData: StatusViewData.Concrete, choices: MutableList<Int>) {
|
||||
val votedPoll = statusViewData.status.actionableStatus.poll!!.votedCopy(choices)
|
||||
updateStatus(statusViewData, votedPoll)
|
||||
timelineCases.voteInPoll(statusViewData.id, votedPoll.id, choices)
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(
|
||||
{ newPoll -> updateStatus(status, newPoll) },
|
||||
{ t -> Log.d(TAG, "Failed to vote in poll: ${status.first.id}", t) }
|
||||
{ newPoll -> updateStatus(statusViewData, newPoll) },
|
||||
{ t -> Log.d(TAG, "Failed to vote in poll: ${statusViewData.id}", t) }
|
||||
)
|
||||
.autoDispose()
|
||||
}
|
||||
|
||||
private fun updateStatus(status: Pair<Status, StatusViewData.Concrete>, newPoll: Poll) {
|
||||
val idx = loadedStatuses.indexOf(status)
|
||||
private fun updateStatus(statusViewData: StatusViewData.Concrete, newPoll: Poll) {
|
||||
val idx = loadedStatuses.indexOf(statusViewData)
|
||||
if (idx >= 0) {
|
||||
val newStatus = status.first.copy(poll = newPoll)
|
||||
val newViewData = status.second.copy(status = newStatus)
|
||||
loadedStatuses[idx] = Pair(newStatus, newViewData)
|
||||
val newStatus = statusViewData.status.copy(poll = newPoll)
|
||||
loadedStatuses[idx] = statusViewData.copy(status = newStatus)
|
||||
statusesPagingSourceFactory.invalidate()
|
||||
}
|
||||
}
|
||||
|
||||
fun favorite(status: Pair<Status, StatusViewData.Concrete>, isFavorited: Boolean) {
|
||||
status.first.favourited = isFavorited
|
||||
fun favorite(statusViewData: StatusViewData.Concrete, isFavorited: Boolean) {
|
||||
statusViewData.status.favourited = isFavorited
|
||||
statusesPagingSourceFactory.invalidate()
|
||||
timelineCases.favourite(status.first.id, isFavorited)
|
||||
.onErrorReturnItem(status.first)
|
||||
timelineCases.favourite(statusViewData.id, isFavorited)
|
||||
.onErrorReturnItem(statusViewData.status)
|
||||
.subscribe()
|
||||
.autoDispose()
|
||||
}
|
||||
|
||||
fun bookmark(status: Pair<Status, StatusViewData.Concrete>, isBookmarked: Boolean) {
|
||||
status.first.bookmarked = isBookmarked
|
||||
fun bookmark(statusViewData: StatusViewData.Concrete, isBookmarked: Boolean) {
|
||||
statusViewData.status.bookmarked = isBookmarked
|
||||
statusesPagingSourceFactory.invalidate()
|
||||
timelineCases.bookmark(status.first.id, isBookmarked)
|
||||
.onErrorReturnItem(status.first)
|
||||
timelineCases.bookmark(statusViewData.id, isBookmarked)
|
||||
.onErrorReturnItem(statusViewData.status)
|
||||
.subscribe()
|
||||
.autoDispose()
|
||||
}
|
||||
|
@ -214,19 +211,15 @@ class SearchViewModel @Inject constructor(
|
|||
return timelineCases.delete(id)
|
||||
}
|
||||
|
||||
fun muteConversation(status: Pair<Status, StatusViewData.Concrete>, mute: Boolean) {
|
||||
val idx = loadedStatuses.indexOf(status)
|
||||
fun muteConversation(statusViewData: StatusViewData.Concrete, mute: Boolean) {
|
||||
val idx = loadedStatuses.indexOf(statusViewData)
|
||||
if (idx >= 0) {
|
||||
val newStatus = status.first.copy(muted = mute)
|
||||
val newPair = Pair(
|
||||
newStatus,
|
||||
status.second.copy(status = newStatus)
|
||||
)
|
||||
loadedStatuses[idx] = newPair
|
||||
val newStatus = statusViewData.status.copy(muted = mute)
|
||||
loadedStatuses[idx] = statusViewData.copy(status = newStatus)
|
||||
statusesPagingSourceFactory.invalidate()
|
||||
}
|
||||
timelineCases.muteConversation(status.first.id, mute)
|
||||
.onErrorReturnItem(status.first)
|
||||
timelineCases.muteConversation(statusViewData.id, mute)
|
||||
.onErrorReturnItem(statusViewData.status)
|
||||
.subscribe()
|
||||
.autoDispose()
|
||||
}
|
||||
|
|
|
@ -21,7 +21,6 @@ import androidx.paging.PagingDataAdapter
|
|||
import androidx.recyclerview.widget.DiffUtil
|
||||
import com.keylesspalace.tusky.R
|
||||
import com.keylesspalace.tusky.adapter.StatusViewHolder
|
||||
import com.keylesspalace.tusky.entity.Status
|
||||
import com.keylesspalace.tusky.interfaces.StatusActionListener
|
||||
import com.keylesspalace.tusky.util.StatusDisplayOptions
|
||||
import com.keylesspalace.tusky.viewdata.StatusViewData
|
||||
|
@ -29,7 +28,7 @@ import com.keylesspalace.tusky.viewdata.StatusViewData
|
|||
class SearchStatusesAdapter(
|
||||
private val statusDisplayOptions: StatusDisplayOptions,
|
||||
private val statusListener: StatusActionListener
|
||||
) : PagingDataAdapter<Pair<Status, StatusViewData.Concrete>, StatusViewHolder>(STATUS_COMPARATOR) {
|
||||
) : PagingDataAdapter<StatusViewData.Concrete, StatusViewHolder>(STATUS_COMPARATOR) {
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): StatusViewHolder {
|
||||
val view = LayoutInflater.from(parent.context)
|
||||
|
@ -39,22 +38,18 @@ class SearchStatusesAdapter(
|
|||
|
||||
override fun onBindViewHolder(holder: StatusViewHolder, position: Int) {
|
||||
getItem(position)?.let { item ->
|
||||
holder.setupWithStatus(item.second, statusListener, statusDisplayOptions)
|
||||
holder.setupWithStatus(item, statusListener, statusDisplayOptions)
|
||||
}
|
||||
}
|
||||
|
||||
fun item(position: Int): Pair<Status, StatusViewData.Concrete>? {
|
||||
return getItem(position)
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
val STATUS_COMPARATOR = object : DiffUtil.ItemCallback<Pair<Status, StatusViewData.Concrete>>() {
|
||||
override fun areContentsTheSame(oldItem: Pair<Status, StatusViewData.Concrete>, newItem: Pair<Status, StatusViewData.Concrete>): Boolean =
|
||||
val STATUS_COMPARATOR = object : DiffUtil.ItemCallback<StatusViewData.Concrete>() {
|
||||
override fun areContentsTheSame(oldItem: StatusViewData.Concrete, newItem: StatusViewData.Concrete): Boolean =
|
||||
oldItem == newItem
|
||||
|
||||
override fun areItemsTheSame(oldItem: Pair<Status, StatusViewData.Concrete>, newItem: Pair<Status, StatusViewData.Concrete>): Boolean =
|
||||
oldItem.second.id == newItem.second.id
|
||||
override fun areItemsTheSame(oldItem: StatusViewData.Concrete, newItem: StatusViewData.Concrete): Boolean =
|
||||
oldItem.id == newItem.id
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -62,15 +62,15 @@ import com.keylesspalace.tusky.viewdata.StatusViewData
|
|||
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
class SearchStatusesFragment : SearchFragment<Pair<Status, StatusViewData.Concrete>>(), StatusActionListener {
|
||||
class SearchStatusesFragment : SearchFragment<StatusViewData.Concrete>(), StatusActionListener {
|
||||
|
||||
override val data: Flow<PagingData<Pair<Status, StatusViewData.Concrete>>>
|
||||
override val data: Flow<PagingData<StatusViewData.Concrete>>
|
||||
get() = viewModel.statusesFlow
|
||||
|
||||
private val searchAdapter
|
||||
get() = super.adapter as SearchStatusesAdapter
|
||||
|
||||
override fun createAdapter(): PagingDataAdapter<Pair<Status, StatusViewData.Concrete>, *> {
|
||||
override fun createAdapter(): PagingDataAdapter<StatusViewData.Concrete, *> {
|
||||
val preferences = PreferenceManager.getDefaultSharedPreferences(binding.searchRecyclerView.context)
|
||||
val statusDisplayOptions = StatusDisplayOptions(
|
||||
animateAvatars = preferences.getBoolean("animateGifAvatars", false),
|
||||
|
@ -91,37 +91,37 @@ class SearchStatusesFragment : SearchFragment<Pair<Status, StatusViewData.Concre
|
|||
}
|
||||
|
||||
override fun onContentHiddenChange(isShowing: Boolean, position: Int) {
|
||||
searchAdapter.item(position)?.let {
|
||||
searchAdapter.peek(position)?.let {
|
||||
viewModel.contentHiddenChange(it, isShowing)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onReply(position: Int) {
|
||||
searchAdapter.item(position)?.first?.let { status ->
|
||||
searchAdapter.peek(position)?.status?.let { status ->
|
||||
reply(status)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onFavourite(favourite: Boolean, position: Int) {
|
||||
searchAdapter.item(position)?.let { status ->
|
||||
searchAdapter.peek(position)?.let { status ->
|
||||
viewModel.favorite(status, favourite)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onBookmark(bookmark: Boolean, position: Int) {
|
||||
searchAdapter.item(position)?.let { status ->
|
||||
searchAdapter.peek(position)?.let { status ->
|
||||
viewModel.bookmark(status, bookmark)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onMore(view: View, position: Int) {
|
||||
searchAdapter.item(position)?.first?.let {
|
||||
searchAdapter.peek(position)?.status?.let {
|
||||
more(it, view, position)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onViewMedia(position: Int, attachmentIndex: Int, view: View?) {
|
||||
searchAdapter.item(position)?.first?.actionableStatus?.let { actionable ->
|
||||
searchAdapter.peek(position)?.status?.actionableStatus?.let { actionable ->
|
||||
when (actionable.attachments[attachmentIndex].type) {
|
||||
Attachment.Type.GIFV, Attachment.Type.VIDEO, Attachment.Type.IMAGE, Attachment.Type.AUDIO -> {
|
||||
val attachments = AttachmentViewData.list(actionable)
|
||||
|
@ -149,20 +149,20 @@ class SearchStatusesFragment : SearchFragment<Pair<Status, StatusViewData.Concre
|
|||
}
|
||||
|
||||
override fun onViewThread(position: Int) {
|
||||
searchAdapter.item(position)?.first?.let { status ->
|
||||
searchAdapter.peek(position)?.status?.let { status ->
|
||||
val actionableStatus = status.actionableStatus
|
||||
bottomSheetActivity?.viewThread(actionableStatus.id, actionableStatus.url)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onOpenReblog(position: Int) {
|
||||
searchAdapter.item(position)?.first?.let { status ->
|
||||
searchAdapter.peek(position)?.status?.let { status ->
|
||||
bottomSheetActivity?.viewAccount(status.account.id)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onExpandedChange(expanded: Boolean, position: Int) {
|
||||
searchAdapter.item(position)?.let {
|
||||
searchAdapter.peek(position)?.let {
|
||||
viewModel.expandedChange(it, expanded)
|
||||
}
|
||||
}
|
||||
|
@ -172,25 +172,25 @@ class SearchStatusesFragment : SearchFragment<Pair<Status, StatusViewData.Concre
|
|||
}
|
||||
|
||||
override fun onContentCollapsedChange(isCollapsed: Boolean, position: Int) {
|
||||
searchAdapter.item(position)?.let {
|
||||
searchAdapter.peek(position)?.let {
|
||||
viewModel.collapsedChange(it, isCollapsed)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onVoteInPoll(position: Int, choices: MutableList<Int>) {
|
||||
searchAdapter.item(position)?.let {
|
||||
searchAdapter.peek(position)?.let {
|
||||
viewModel.voteInPoll(it, choices)
|
||||
}
|
||||
}
|
||||
|
||||
private fun removeItem(position: Int) {
|
||||
searchAdapter.item(position)?.let {
|
||||
searchAdapter.peek(position)?.let {
|
||||
viewModel.removeItem(it)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onReblog(reblog: Boolean, position: Int) {
|
||||
searchAdapter.item(position)?.let { status ->
|
||||
searchAdapter.peek(position)?.let { status ->
|
||||
viewModel.reblog(status, reblog)
|
||||
}
|
||||
}
|
||||
|
@ -316,7 +316,7 @@ class SearchStatusesFragment : SearchFragment<Pair<Status, StatusViewData.Concre
|
|||
return@setOnMenuItemClickListener true
|
||||
}
|
||||
R.id.status_mute_conversation -> {
|
||||
searchAdapter.item(position)?.let { foundStatus ->
|
||||
searchAdapter.peek(position)?.let { foundStatus ->
|
||||
viewModel.muteConversation(foundStatus, status.muted != true)
|
||||
}
|
||||
return@setOnMenuItemClickListener true
|
||||
|
|
Loading…
Reference in a new issue