Add new name collision state management.

This commit is contained in:
Alex Hart
2024-04-18 15:53:39 -03:00
committed by Greyson Parrelli
parent 62cf3feeaa
commit 15d8a698c5
17 changed files with 861 additions and 164 deletions

View File

@@ -120,6 +120,7 @@ class ConversationBannerView @JvmOverloads constructor(
setOnHideListener {
clearRequestReview()
listener?.onDismissReview()
true
}
}
@@ -194,5 +195,6 @@ class ConversationBannerView @JvmOverloads constructor(
fun onUnverifiedBannerDismissed(unverifiedIdentities: List<IdentityRecord>)
fun onRequestReviewIndividual(recipientId: RecipientId)
fun onReviewGroupMembers(groupId: GroupId.V2)
fun onDismissReview()
}
}

View File

@@ -423,7 +423,7 @@ class ConversationFragment :
private val conversationGroupViewModel: ConversationGroupViewModel by viewModels(
factoryProducer = {
ConversationGroupViewModel.Factory(args.threadId, conversationRecipientRepository)
ConversationGroupViewModel.Factory(conversationRecipientRepository)
}
)
@@ -3704,6 +3704,10 @@ class ConversationFragment :
override fun onReviewGroupMembers(groupId: GroupId.V2) {
ReviewCardDialogFragment.createForReviewMembers(groupId).show(childFragmentManager, null)
}
override fun onDismissReview() {
viewModel.onDismissReview()
}
}
//endregion

View File

@@ -82,7 +82,7 @@ import org.thoughtcrime.securesms.mms.PartAuthority
import org.thoughtcrime.securesms.mms.QuoteModel
import org.thoughtcrime.securesms.mms.Slide
import org.thoughtcrime.securesms.mms.SlideDeck
import org.thoughtcrime.securesms.profiles.spoofing.ReviewUtil
import org.thoughtcrime.securesms.profiles.spoofing.ReviewRecipient
import org.thoughtcrime.securesms.providers.BlobProvider
import org.thoughtcrime.securesms.recipients.Recipient
import org.thoughtcrime.securesms.recipients.RecipientId
@@ -363,6 +363,12 @@ class ConversationRepository(
}.subscribeOn(Schedulers.io())
}
fun dismissRequestReviewState(threadRecipientId: RecipientId) {
SignalExecutors.BOUNDED_IO.execute {
SignalDatabase.nameCollisions.markCollisionsForThreadRecipientDismissed(threadRecipientId)
}
}
fun getRequestReviewState(recipient: Recipient, group: GroupRecord?, messageRequest: MessageRequestState): Single<RequestReviewState> {
return Single.fromCallable {
if (group == null && messageRequest.state != MessageRequestState.State.INDIVIDUAL) {
@@ -370,12 +376,12 @@ class ConversationRepository(
}
if (group == null) {
val recipientsToReview = ReviewUtil.getRecipientsToPromptForReview(recipient.id)
if (recipientsToReview.size > 0) {
val recipientsToReview = SignalDatabase.nameCollisions.getCollisionsForThreadRecipientId(recipient.id)
if (recipientsToReview.isNotEmpty()) {
return@fromCallable RequestReviewState(
individualReviewState = IndividualReviewState(
target = recipient,
firstDuplicate = Recipient.resolvedList(recipientsToReview)[0]
firstDuplicate = recipientsToReview.first().recipient
)
)
}
@@ -383,14 +389,14 @@ class ConversationRepository(
if (group != null && group.isV2Group) {
val groupId = group.id.requireV2()
val duplicateRecipients: List<Recipient> = ReviewUtil.getDuplicatedRecipients(groupId).map { it.recipient }
val duplicateRecipients: List<ReviewRecipient> = SignalDatabase.nameCollisions.getCollisionsForThreadRecipientId(group.recipientId)
if (duplicateRecipients.isNotEmpty()) {
return@fromCallable RequestReviewState(
groupReviewState = GroupReviewState(
groupId,
duplicateRecipients[0],
duplicateRecipients[1],
duplicateRecipients[0].recipient,
duplicateRecipients[1].recipient,
duplicateRecipients.size
)
)

View File

@@ -291,6 +291,11 @@ class ConversationViewModel(
refreshReminder.onNext(Unit)
}
fun onDismissReview() {
val recipientId = recipientSnapshot?.id ?: return
repository.dismissRequestReviewState(recipientId)
}
override fun onCleared() {
disposables.clear()
startExpiration.onComplete()

View File

@@ -4,7 +4,6 @@ import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
import io.reactivex.rxjava3.core.Maybe
import io.reactivex.rxjava3.core.Observable
import io.reactivex.rxjava3.core.Single
import io.reactivex.rxjava3.disposables.CompositeDisposable
import io.reactivex.rxjava3.kotlin.addTo
@@ -25,21 +24,23 @@ import org.thoughtcrime.securesms.groups.v2.GroupManagementRepository
import org.thoughtcrime.securesms.jobs.ForceUpdateGroupV2Job
import org.thoughtcrime.securesms.jobs.GroupV2UpdateSelfProfileKeyJob
import org.thoughtcrime.securesms.jobs.RequestGroupV2InfoJob
import org.thoughtcrime.securesms.profiles.spoofing.ReviewUtil
import org.thoughtcrime.securesms.recipients.Recipient
/**
* Manages group state and actions for conversations.
*/
class ConversationGroupViewModel(
private val threadId: Long,
private val groupManagementRepository: GroupManagementRepository = GroupManagementRepository(),
private val recipientRepository: ConversationRecipientRepository
) : ViewModel() {
private val disposables = CompositeDisposable()
private val _groupRecord: BehaviorSubject<GroupRecord>
private val _reviewState: Subject<ConversationGroupReviewState>
private val _groupRecord: BehaviorSubject<GroupRecord> = recipientRepository
.groupRecord
.filter { it.isPresent }
.map { it.get() }
.subscribeWithSubject(BehaviorSubject.create(), disposables)
private val _groupActiveState: Subject<ConversationGroupActiveState> = BehaviorSubject.create()
private val _memberLevel: BehaviorSubject<ConversationGroupMemberLevel> = BehaviorSubject.create()
@@ -50,28 +51,6 @@ class ConversationGroupViewModel(
get() = _groupRecord.value
init {
_groupRecord = recipientRepository
.groupRecord
.filter { it.isPresent }
.map { it.get() }
.subscribeWithSubject(BehaviorSubject.create(), disposables)
val duplicates = _groupRecord.map { groupRecord ->
if (groupRecord.isV2Group) {
ReviewUtil.getDuplicatedRecipients(groupRecord.id.requireV2()).map { it.recipient }
} else {
emptyList()
}
}
_reviewState = Observable.combineLatest(_groupRecord, duplicates) { record, dupes ->
if (dupes.isEmpty()) {
ConversationGroupReviewState.EMPTY
} else {
ConversationGroupReviewState(record.id.requireV2(), dupes[0], dupes.size)
}
}.subscribeWithSubject(BehaviorSubject.create(), disposables)
disposables += _groupRecord.subscribe { groupRecord ->
_groupActiveState.onNext(ConversationGroupActiveState(groupRecord.isActive, groupRecord.isV2Group))
_memberLevel.onNext(ConversationGroupMemberLevel(groupRecord.memberLevel(Recipient.self()), groupRecord.isAnnouncementGroup))
@@ -154,9 +133,9 @@ class ConversationGroupViewModel(
.addTo(disposables)
}
class Factory(private val threadId: Long, private val recipientRepository: ConversationRecipientRepository) : ViewModelProvider.Factory {
class Factory(private val recipientRepository: ConversationRecipientRepository) : ViewModelProvider.Factory {
override fun <T : ViewModel> create(modelClass: Class<T>): T {
return modelClass.cast(ConversationGroupViewModel(threadId, recipientRepository = recipientRepository)) as T
return modelClass.cast(ConversationGroupViewModel(recipientRepository = recipientRepository)) as T
}
}
}