From 2960a85ff1570ca49fda25b1b889fdd0837b0f28 Mon Sep 17 00:00:00 2001 From: Konrad Pozniak Date: Fri, 25 Feb 2022 18:57:49 +0100 Subject: [PATCH] use ViewData only instead of Pair in Search (#2336) --- .../components/search/SearchViewModel.kt | 97 +++++++++---------- .../search/adapter/SearchStatusesAdapter.kt | 17 ++-- .../fragments/SearchStatusesFragment.kt | 34 +++---- 3 files changed, 68 insertions(+), 80 deletions(-) diff --git a/app/src/main/java/com/keylesspalace/tusky/components/search/SearchViewModel.kt b/app/src/main/java/com/keylesspalace/tusky/components/search/SearchViewModel.kt index e87c0c41..065aa040 100644 --- a/app/src/main/java/com/keylesspalace/tusky/components/search/SearchViewModel.kt +++ b/app/src/main/java/com/keylesspalace/tusky/components/search/SearchViewModel.kt @@ -53,17 +53,15 @@ class SearchViewModel @Inject constructor( val alwaysShowSensitiveMedia = activeAccount?.alwaysShowSensitiveMedia ?: false val alwaysOpenSpoiler = activeAccount?.alwaysOpenSpoiler ?: false - private val loadedStatuses: MutableList> = mutableListOf() + private val loadedStatuses: MutableList = 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) { - 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, 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, 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, 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, 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, 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, choices: MutableList) { - 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) { + 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, 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, 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, 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, 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() } diff --git a/app/src/main/java/com/keylesspalace/tusky/components/search/adapter/SearchStatusesAdapter.kt b/app/src/main/java/com/keylesspalace/tusky/components/search/adapter/SearchStatusesAdapter.kt index d1ad3586..a7c4c90e 100644 --- a/app/src/main/java/com/keylesspalace/tusky/components/search/adapter/SearchStatusesAdapter.kt +++ b/app/src/main/java/com/keylesspalace/tusky/components/search/adapter/SearchStatusesAdapter.kt @@ -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, StatusViewHolder>(STATUS_COMPARATOR) { +) : PagingDataAdapter(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? { - return getItem(position) - } - companion object { - val STATUS_COMPARATOR = object : DiffUtil.ItemCallback>() { - override fun areContentsTheSame(oldItem: Pair, newItem: Pair): Boolean = + val STATUS_COMPARATOR = object : DiffUtil.ItemCallback() { + override fun areContentsTheSame(oldItem: StatusViewData.Concrete, newItem: StatusViewData.Concrete): Boolean = oldItem == newItem - override fun areItemsTheSame(oldItem: Pair, newItem: Pair): Boolean = - oldItem.second.id == newItem.second.id + override fun areItemsTheSame(oldItem: StatusViewData.Concrete, newItem: StatusViewData.Concrete): Boolean = + oldItem.id == newItem.id } } } diff --git a/app/src/main/java/com/keylesspalace/tusky/components/search/fragments/SearchStatusesFragment.kt b/app/src/main/java/com/keylesspalace/tusky/components/search/fragments/SearchStatusesFragment.kt index 4955d474..8469b57d 100644 --- a/app/src/main/java/com/keylesspalace/tusky/components/search/fragments/SearchStatusesFragment.kt +++ b/app/src/main/java/com/keylesspalace/tusky/components/search/fragments/SearchStatusesFragment.kt @@ -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>(), StatusActionListener { +class SearchStatusesFragment : SearchFragment(), StatusActionListener { - override val data: Flow>> + override val data: Flow> get() = viewModel.statusesFlow private val searchAdapter get() = super.adapter as SearchStatusesAdapter - override fun createAdapter(): PagingDataAdapter, *> { + override fun createAdapter(): PagingDataAdapter { val preferences = PreferenceManager.getDefaultSharedPreferences(binding.searchRecyclerView.context) val statusDisplayOptions = StatusDisplayOptions( animateAvatars = preferences.getBoolean("animateGifAvatars", false), @@ -91,37 +91,37 @@ class SearchStatusesFragment : SearchFragment + 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 + 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) { - 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 { - searchAdapter.item(position)?.let { foundStatus -> + searchAdapter.peek(position)?.let { foundStatus -> viewModel.muteConversation(foundStatus, status.muted != true) } return@setOnMenuItemClickListener true