Send 'clear history' event when clearing the call log.

This commit is contained in:
Alex Hart
2023-08-01 16:13:37 -03:00
committed by Greyson Parrelli
parent d3f073e573
commit e239036d8b
11 changed files with 319 additions and 42 deletions

View File

@@ -10,6 +10,7 @@ import io.reactivex.rxjava3.schedulers.Schedulers
import org.signal.ringrtc.CallLinkState
import org.thoughtcrime.securesms.database.SignalDatabase
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies
import org.thoughtcrime.securesms.jobs.CallLinkUpdateSendJob
import org.thoughtcrime.securesms.service.webrtc.links.CallLinkCredentials
import org.thoughtcrime.securesms.service.webrtc.links.SignalCallLinkManager
import org.thoughtcrime.securesms.service.webrtc.links.UpdateCallLinkResult
@@ -58,6 +59,7 @@ class UpdateCallLinkRepository(
return { result ->
if (result is UpdateCallLinkResult.Success) {
SignalDatabase.callLinks.updateCallLinkState(credentials.roomId, result.state)
ApplicationDependencies.getJobManager().add(CallLinkUpdateSendJob(credentials.roomId))
}
}
}

View File

@@ -5,11 +5,14 @@ import io.reactivex.rxjava3.core.Observable
import io.reactivex.rxjava3.core.Single
import io.reactivex.rxjava3.schedulers.Schedulers
import org.signal.core.util.concurrent.SignalExecutors
import org.signal.core.util.withinTransaction
import org.thoughtcrime.securesms.calls.links.UpdateCallLinkRepository
import org.thoughtcrime.securesms.database.CallLinkTable
import org.thoughtcrime.securesms.database.DatabaseObserver
import org.thoughtcrime.securesms.database.SignalDatabase
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies
import org.thoughtcrime.securesms.jobs.CallLinkPeekJob
import org.thoughtcrime.securesms.jobs.CallLogEventSendJob
import org.thoughtcrime.securesms.service.webrtc.links.CallLinkRoomId
import org.thoughtcrime.securesms.service.webrtc.links.UpdateCallLinkResult
@@ -80,6 +83,23 @@ class CallLogRepository(
}.subscribeOn(Schedulers.io())
}
/**
* Delete all call events / unowned links and enqueue clear history job, and then
* emit a clear history message.
*/
fun deleteAllCallLogsOnOrBeforeNow(): Single<Int> {
return Single.fromCallable {
SignalDatabase.rawDatabase.withinTransaction {
val now = System.currentTimeMillis()
SignalDatabase.calls.deleteNonAdHocCallEventsOnOrBefore(now)
SignalDatabase.callLinks.deleteNonAdminCallLinksOnOrBefore(now)
ApplicationDependencies.getJobManager().add(CallLogEventSendJob.forClearHistory(now))
}
SignalDatabase.callLinks.getAllAdminCallLinksExcept(emptySet())
}.flatMap(this::revokeAndCollectResults).map { -1 }.subscribeOn(Schedulers.io())
}
/**
* Deletes the selected call links. We DELETE those links we don't have admin keys for,
* and revoke the ones we *do* have admin keys for. We then perform a cleanup step on
@@ -93,19 +113,7 @@ class CallLogRepository(
val allCallLinkIds = SignalDatabase.calls.getCallLinkRoomIdsFromCallRowIds(selectedCallRowIds) + selectedRoomIds
SignalDatabase.callLinks.deleteNonAdminCallLinks(allCallLinkIds)
SignalDatabase.callLinks.getAdminCallLinks(allCallLinkIds)
}.flatMap { callLinksToRevoke ->
Single.merge(
callLinksToRevoke.map {
updateCallLinkRepository.revokeCallLink(it.credentials!!)
}
).reduce(0) { acc, current ->
acc + (if (current is UpdateCallLinkResult.Success) 0 else 1)
}
}.doOnTerminate {
SignalDatabase.calls.updateAdHocCallEventDeletionTimestamps()
}.doOnDispose {
SignalDatabase.calls.updateAdHocCallEventDeletionTimestamps()
}.subscribeOn(Schedulers.io())
}.flatMap(this::revokeAndCollectResults).subscribeOn(Schedulers.io())
}
/**
@@ -121,19 +129,21 @@ class CallLogRepository(
val allCallLinkIds = SignalDatabase.calls.getCallLinkRoomIdsFromCallRowIds(selectedCallRowIds) + selectedRoomIds
SignalDatabase.callLinks.deleteAllNonAdminCallLinksExcept(allCallLinkIds)
SignalDatabase.callLinks.getAllAdminCallLinksExcept(allCallLinkIds)
}.flatMap { callLinksToRevoke ->
Single.merge(
callLinksToRevoke.map {
updateCallLinkRepository.revokeCallLink(it.credentials!!)
}
).reduce(0) { acc, current ->
acc + (if (current is UpdateCallLinkResult.Success) 0 else 1)
}.flatMap(this::revokeAndCollectResults).subscribeOn(Schedulers.io())
}
private fun revokeAndCollectResults(callLinksToRevoke: Set<CallLinkTable.CallLink>): Single<Int> {
return Single.merge(
callLinksToRevoke.map {
updateCallLinkRepository.revokeCallLink(it.credentials!!)
}
).reduce(0) { acc, current ->
acc + (if (current is UpdateCallLinkResult.Success) 0 else 1)
}.doOnTerminate {
SignalDatabase.calls.updateAdHocCallEventDeletionTimestamps()
}.doOnDispose {
SignalDatabase.calls.updateAdHocCallEventDeletionTimestamps()
}.subscribeOn(Schedulers.io())
}
}
fun peekCallLinks(): Completable {

View File

@@ -3,17 +3,17 @@ package org.thoughtcrime.securesms.calls.log
/**
* Selection state object for call logs.
*/
sealed class CallLogSelectionState {
abstract fun contains(callId: CallLogRow.Id): Boolean
abstract fun isNotEmpty(totalCount: Int): Boolean
sealed interface CallLogSelectionState {
fun contains(callId: CallLogRow.Id): Boolean
fun isNotEmpty(totalCount: Int): Boolean
abstract fun count(totalCount: Int): Int
fun count(totalCount: Int): Int
abstract fun selected(): Set<CallLogRow.Id>
fun selected(): Set<CallLogRow.Id>
fun isExclusionary(): Boolean = this is Excludes
protected abstract fun select(callId: CallLogRow.Id): CallLogSelectionState
protected abstract fun deselect(callId: CallLogRow.Id): CallLogSelectionState
fun select(callId: CallLogRow.Id): CallLogSelectionState
fun deselect(callId: CallLogRow.Id): CallLogSelectionState
fun toggle(callId: CallLogRow.Id): CallLogSelectionState {
return if (contains(callId)) {
@@ -26,7 +26,7 @@ sealed class CallLogSelectionState {
/**
* Includes contains an opt-in list of call logs.
*/
data class Includes(private val includes: Set<CallLogRow.Id>) : CallLogSelectionState() {
data class Includes(private val includes: Set<CallLogRow.Id>) : CallLogSelectionState {
override fun contains(callId: CallLogRow.Id): Boolean {
return includes.contains(callId)
}
@@ -55,7 +55,7 @@ sealed class CallLogSelectionState {
/**
* Excludes contains an opt-out list of call logs.
*/
data class Excludes(private val excluded: Set<CallLogRow.Id>) : CallLogSelectionState() {
data class Excludes(private val excluded: Set<CallLogRow.Id>) : CallLogSelectionState {
override fun contains(callId: CallLogRow.Id): Boolean = !excluded.contains(callId)
override fun isNotEmpty(totalCount: Int): Boolean = excluded.size < totalCount
@@ -74,8 +74,10 @@ sealed class CallLogSelectionState {
override fun selected(): Set<CallLogRow.Id> = excluded
}
object All : CallLogSelectionState by Excludes(emptySet())
companion object {
fun empty(): CallLogSelectionState = Includes(emptySet())
fun selectAll(): CallLogSelectionState = Excludes(emptySet())
fun selectAll(): CallLogSelectionState = All
}
}

View File

@@ -35,14 +35,21 @@ class CallLogStagedDeletion(
.map { it.roomId }
.toSet()
return if (stateSnapshot.isExclusionary()) {
repository.deleteAllCallLogsExcept(callRowIds, filter == CallLogFilter.MISSED).andThen(
repository.deleteAllCallLinksExcept(callRowIds, callLinkIds)
)
} else {
repository.deleteSelectedCallLogs(callRowIds).andThen(
repository.deleteSelectedCallLinks(callRowIds, callLinkIds)
)
return when {
stateSnapshot is CallLogSelectionState.All && filter == CallLogFilter.ALL -> {
repository.deleteAllCallLogsOnOrBeforeNow()
}
stateSnapshot is CallLogSelectionState.Excludes || stateSnapshot is CallLogSelectionState.All -> {
repository.deleteAllCallLogsExcept(callRowIds, filter == CallLogFilter.MISSED).andThen(
repository.deleteAllCallLinksExcept(callRowIds, callLinkIds)
)
}
stateSnapshot is CallLogSelectionState.Includes -> {
repository.deleteSelectedCallLogs(callRowIds).andThen(
repository.deleteSelectedCallLinks(callRowIds, callLinkIds)
)
}
else -> error("Unhandled state $stateSnapshot $filter")
}
}
}