Add proper selection state support to Chats and Calls tabs.

This commit is contained in:
Alex Hart
2025-10-15 14:45:05 -03:00
committed by Cody Henthorne
parent e57b47ec82
commit cbe72307a0
6 changed files with 62 additions and 22 deletions

View File

@@ -92,6 +92,7 @@ class CallLogAdapter(
fun submitCallRows(
rows: List<CallLogRow?>,
selectionState: CallLogSelectionState,
activeCallLogRowId: CallLogRow.Id?,
localCallRecipientId: RecipientId,
onCommit: () -> Unit
): Int {
@@ -99,8 +100,19 @@ class CallLogAdapter(
.filterNotNull()
.map {
when (it) {
is CallLogRow.Call -> CallModel(it, selectionState, itemCount, it.peer.id == localCallRecipientId)
is CallLogRow.CallLink -> CallLinkModel(it, selectionState, itemCount, it.recipient.id == localCallRecipientId)
is CallLogRow.Call -> CallModel(
call = it,
selectionState = selectionState,
itemCount = itemCount,
isLocalDeviceInCall = it.peer.id == localCallRecipientId
)
is CallLogRow.CallLink -> CallLinkModel(
callLink = it,
selectionState = selectionState,
activeCallLogRowId = activeCallLogRowId,
itemCount = itemCount,
isLocalDeviceInCall = it.recipient.id == localCallRecipientId
)
is CallLogRow.ClearFilter -> ClearFilterModel()
is CallLogRow.ClearFilterEmpty -> ClearFilterEmptyModel()
is CallLogRow.CreateCallLink -> CreateCallLinkModel()
@@ -148,6 +160,7 @@ class CallLogAdapter(
private class CallLinkModel(
val callLink: CallLogRow.CallLink,
val selectionState: CallLogSelectionState,
val activeCallLogRowId: CallLogRow.Id?,
val itemCount: Int,
val isLocalDeviceInCall: Boolean
) : MappingModel<CallLinkModel> {
@@ -159,12 +172,13 @@ class CallLogAdapter(
override fun areContentsTheSame(newItem: CallLinkModel): Boolean {
return callLink == newItem.callLink &&
isSelectionStateTheSame(newItem) &&
isActiveIdStateTheSame(newItem) &&
isItemCountTheSame(newItem) &&
isLocalDeviceInCall == newItem.isLocalDeviceInCall
}
override fun getChangePayload(newItem: CallLinkModel): Any? {
return if (callLink == newItem.callLink && (!isSelectionStateTheSame(newItem) || !isItemCountTheSame(newItem))) {
return if (callLink == newItem.callLink && (!isSelectionStateTheSame(newItem) || !isItemCountTheSame(newItem) || !isActiveIdStateTheSame(newItem))) {
PAYLOAD_SELECTION_STATE
} else {
null
@@ -176,6 +190,13 @@ class CallLogAdapter(
selectionState.isNotEmpty(itemCount) == newItem.selectionState.isNotEmpty(newItem.itemCount)
}
private fun isActiveIdStateTheSame(newItem: CallLinkModel): Boolean {
val isOldItemActive = activeCallLogRowId == callLink.id
val isNewItemActive = newItem.activeCallLogRowId == newItem.callLink.id
return (isOldItemActive && isNewItemActive) || (!isOldItemActive && !isNewItemActive)
}
private fun isItemCountTheSame(newItem: CallLinkModel): Boolean {
return itemCount == newItem.itemCount
}
@@ -220,6 +241,8 @@ class CallLogAdapter(
binding.callSelected.isChecked = model.selectionState.contains(model.callLink.id)
binding.callSelected.visible = model.selectionState.isNotEmpty(model.itemCount)
itemView.isActivated = model.activeCallLogRowId == model.callLink.id
if (payload.isNotEmpty()) {
return
}

View File

@@ -18,6 +18,7 @@ import androidx.recyclerview.widget.RecyclerView
import com.google.android.material.appbar.AppBarLayout
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
import io.reactivex.rxjava3.core.BackpressureStrategy
import io.reactivex.rxjava3.kotlin.Flowables
import io.reactivex.rxjava3.kotlin.subscribeBy
import kotlinx.coroutines.launch
@@ -25,6 +26,7 @@ import org.signal.core.util.DimensionUnit
import org.signal.core.util.concurrent.LifecycleDisposable
import org.signal.core.util.concurrent.addTo
import org.signal.core.util.logging.Log
import org.signal.core.util.orNull
import org.thoughtcrime.securesms.MainNavigator
import org.thoughtcrime.securesms.R
import org.thoughtcrime.securesms.calls.links.create.CreateCallLinkBottomSheetDialogFragment
@@ -122,12 +124,13 @@ class CallLogFragment : Fragment(R.layout.call_log_fragment), CallLogAdapter.Cal
)
disposables += scrollToPositionDelegate
disposables += Flowables.combineLatest(viewModel.data, viewModel.selected)
disposables += Flowables.combineLatest(viewModel.data, viewModel.selected, mainNavigationViewModel.observableActiveCallId.toFlowable(BackpressureStrategy.LATEST))
.observeOn(AndroidSchedulers.mainThread())
.subscribe { (data, selected) ->
.subscribe { (data, selected, activeRowId) ->
val filteredCount = callLogAdapter.submitCallRows(
data,
selected,
activeCallLogRowId = activeRowId.orNull().takeIf { resources.getWindowSizeClass().isSplitPane() },
viewModel.callLogPeekHelper.localDeviceCallRecipientId,
scrollToPositionDelegate::notifyListCommitted
)