diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/settings/conversation/InternalConversationSettingsFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/components/settings/conversation/InternalConversationSettingsFragment.kt index a3e6033802..9636d3fd1d 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/settings/conversation/InternalConversationSettingsFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/components/settings/conversation/InternalConversationSettingsFragment.kt @@ -14,6 +14,7 @@ import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.update import org.signal.core.util.concurrent.SignalExecutors import org.signal.core.util.isAbsent +import org.signal.core.util.logging.Log import org.signal.core.util.orNull import org.signal.core.util.roundedString import org.signal.core.util.withinTransaction @@ -47,6 +48,10 @@ import kotlin.time.DurationUnit @Stable class InternalConversationSettingsFragment : ComposeFragment(), InternalConversationSettingsScreenCallbacks { + companion object { + val TAG = Log.tag(InternalConversationSettingsFragment::class.java) + } + private val viewModel: InternalViewModel by viewModels( factoryProducer = { val recipientId = InternalConversationSettingsFragmentArgs.fromBundle(requireArguments()).recipientId @@ -250,6 +255,21 @@ class InternalConversationSettingsFragment : ComposeFragment(), InternalConversa Toast.makeText(context, "Done! Split the ACI and profile key off into $aciRecipientId", Toast.LENGTH_SHORT).show() } + override fun clearSenderKey(recipientId: RecipientId) { + val group = SignalDatabase.groups.getGroup(recipientId).orNull() + if (group == null) { + Log.w(TAG, "Couldn't find group for recipientId: $recipientId") + return + } + + if (group.distributionId == null) { + Log.w(TAG, "No distributionId for recipientId: $recipientId") + return + } + + SignalDatabase.senderKeyShared.deleteAllFor(group.distributionId) + } + class InternalViewModel( val recipientId: RecipientId ) : ViewModel(), RecipientForeverObserver { diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/settings/conversation/InternalConversationSettingsScreen.kt b/app/src/main/java/org/thoughtcrime/securesms/components/settings/conversation/InternalConversationSettingsScreen.kt index 10b4f58f83..5bc2953e75 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/settings/conversation/InternalConversationSettingsScreen.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/components/settings/conversation/InternalConversationSettingsScreen.kt @@ -33,6 +33,7 @@ import org.thoughtcrime.securesms.recipients.RecipientId private enum class Dialog { NONE, DISABLE_PROFILE_SHARING, + CLEAR_SENDER_KEY, DELETE_SESSIONS, ARCHIVE_SESSIONS, DELETE_AVATAR, @@ -193,11 +194,21 @@ fun InternalConversationSettingsScreen( ) } - if (!state.isGroup) { - item { - Texts.SectionHeader(text = "Actions") - } + item { + Texts.SectionHeader(text = "Actions") + } + if (state.isGroup) { + item { + Rows.TextRow( + text = "Clear sender key", + label = "Resets any sender key state, meaning the next message will require re-distributing sender key material.", + onClick = { + dialog = Dialog.CLEAR_SENDER_KEY + } + ) + } + } else { item { Rows.TextRow( text = "Disable Profile Sharing", @@ -362,6 +373,9 @@ private fun rememberOnConfirm( Dialog.SPLIT_WITHOUT_CREATING_THREADS -> { { callbacks.splitWithoutCreatingThreads(state.recipientId) } } + Dialog.CLEAR_SENDER_KEY -> { + { callbacks.clearSenderKey(state.recipientId) } + } } } } @@ -459,6 +473,7 @@ interface InternalConversationSettingsScreenCallbacks { fun add10Messages(recipientId: RecipientId) = Unit fun splitAndCreateThreads(recipientId: RecipientId) = Unit fun splitWithoutCreatingThreads(recipientId: RecipientId) = Unit + fun clearSenderKey(recipientId: RecipientId) = Unit object Empty : InternalConversationSettingsScreenCallbacks }