mirror of
https://github.com/oxen-io/session-android.git
synced 2024-11-25 11:05:25 +00:00
Tidy up
This commit is contained in:
parent
0657ab2305
commit
88df9ff65a
@ -196,12 +196,14 @@ class ConfigToDatabaseSync @Inject constructor(
|
|||||||
private data class UpdateGroupInfo(
|
private data class UpdateGroupInfo(
|
||||||
val id: AccountId,
|
val id: AccountId,
|
||||||
val name: String?,
|
val name: String?,
|
||||||
|
val destroyed: Boolean,
|
||||||
val deleteBefore: Long?,
|
val deleteBefore: Long?,
|
||||||
val deleteAttachmentsBefore: Long?
|
val deleteAttachmentsBefore: Long?
|
||||||
) {
|
) {
|
||||||
constructor(groupInfoConfig: ReadableGroupInfoConfig) : this(
|
constructor(groupInfoConfig: ReadableGroupInfoConfig) : this(
|
||||||
id = groupInfoConfig.id(),
|
id = groupInfoConfig.id(),
|
||||||
name = groupInfoConfig.getName(),
|
name = groupInfoConfig.getName(),
|
||||||
|
destroyed = groupInfoConfig.isDestroyed(),
|
||||||
deleteBefore = groupInfoConfig.getDeleteBefore(),
|
deleteBefore = groupInfoConfig.getDeleteBefore(),
|
||||||
deleteAttachmentsBefore = groupInfoConfig.getDeleteAttachmentsBefore()
|
deleteAttachmentsBefore = groupInfoConfig.getDeleteAttachmentsBefore()
|
||||||
)
|
)
|
||||||
@ -212,6 +214,10 @@ class ConfigToDatabaseSync @Inject constructor(
|
|||||||
val recipient = storage.getRecipientForThread(threadId) ?: return
|
val recipient = storage.getRecipientForThread(threadId) ?: return
|
||||||
recipientDatabase.setProfileName(recipient, groupInfoConfig.name)
|
recipientDatabase.setProfileName(recipient, groupInfoConfig.name)
|
||||||
profileManager.setName(context, recipient, groupInfoConfig.name ?: "")
|
profileManager.setName(context, recipient, groupInfoConfig.name ?: "")
|
||||||
|
|
||||||
|
if (groupInfoConfig.destroyed) {
|
||||||
|
storage.clearMessages(threadId)
|
||||||
|
} else {
|
||||||
groupInfoConfig.deleteBefore?.let { removeBefore ->
|
groupInfoConfig.deleteBefore?.let { removeBefore ->
|
||||||
storage.trimThreadBefore(threadId, removeBefore)
|
storage.trimThreadBefore(threadId, removeBefore)
|
||||||
}
|
}
|
||||||
@ -219,6 +225,7 @@ class ConfigToDatabaseSync @Inject constructor(
|
|||||||
mmsDatabase.deleteMessagesInThreadBeforeDate(threadId, removeAttachmentsBefore, onlyMedia = true)
|
mmsDatabase.deleteMessagesInThreadBeforeDate(threadId, removeAttachmentsBefore, onlyMedia = true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private data class UpdateContacts(val contacts: List<Contact>)
|
private data class UpdateContacts(val contacts: List<Contact>)
|
||||||
|
|
||||||
|
@ -1231,17 +1231,8 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
|
|||||||
if (item.itemId == android.R.id.home) {
|
if (item.itemId == android.R.id.home) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return viewModel.recipient?.let { recipient ->
|
|
||||||
ConversationMenuHelper.onOptionItemSelected(
|
return viewModel.onOptionItemSelected(this, item)
|
||||||
context = this,
|
|
||||||
item = item,
|
|
||||||
thread = recipient,
|
|
||||||
threadID = threadId,
|
|
||||||
factory = configFactory,
|
|
||||||
storage = storage,
|
|
||||||
groupManager = groupManagerV2,
|
|
||||||
)
|
|
||||||
} ?: false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun block(deleteThread: Boolean) {
|
override fun block(deleteThread: Boolean) {
|
||||||
|
@ -2,6 +2,7 @@ package org.thoughtcrime.securesms.conversation.v2
|
|||||||
|
|
||||||
import android.app.Application
|
import android.app.Application
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
import android.view.MenuItem
|
||||||
import androidx.annotation.StringRes
|
import androidx.annotation.StringRes
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
@ -13,11 +14,8 @@ import dagger.assisted.AssistedInject
|
|||||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.GlobalScope
|
import kotlinx.coroutines.GlobalScope
|
||||||
import kotlinx.coroutines.Job
|
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
import kotlinx.coroutines.flow.filterNotNull
|
|
||||||
import kotlinx.coroutines.flow.map
|
|
||||||
import kotlinx.coroutines.flow.update
|
import kotlinx.coroutines.flow.update
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
@ -25,6 +23,7 @@ import network.loki.messenger.R
|
|||||||
import network.loki.messenger.libsession_util.util.GroupMember
|
import network.loki.messenger.libsession_util.util.GroupMember
|
||||||
import org.session.libsession.database.MessageDataProvider
|
import org.session.libsession.database.MessageDataProvider
|
||||||
import org.session.libsession.database.StorageProtocol
|
import org.session.libsession.database.StorageProtocol
|
||||||
|
import org.session.libsession.messaging.groups.GroupManagerV2
|
||||||
import org.session.libsession.messaging.messages.ExpirationConfiguration
|
import org.session.libsession.messaging.messages.ExpirationConfiguration
|
||||||
import org.session.libsession.messaging.open_groups.OpenGroup
|
import org.session.libsession.messaging.open_groups.OpenGroup
|
||||||
import org.session.libsession.messaging.open_groups.OpenGroupApi
|
import org.session.libsession.messaging.open_groups.OpenGroupApi
|
||||||
@ -40,12 +39,14 @@ import org.session.libsignal.utilities.IdPrefix
|
|||||||
import org.session.libsignal.utilities.Log
|
import org.session.libsignal.utilities.Log
|
||||||
import org.session.libsignal.utilities.AccountId
|
import org.session.libsignal.utilities.AccountId
|
||||||
import org.thoughtcrime.securesms.audio.AudioSlidePlayer
|
import org.thoughtcrime.securesms.audio.AudioSlidePlayer
|
||||||
|
import org.thoughtcrime.securesms.conversation.v2.menus.ConversationMenuHelper
|
||||||
import org.thoughtcrime.securesms.database.GroupDatabase
|
import org.thoughtcrime.securesms.database.GroupDatabase
|
||||||
import org.thoughtcrime.securesms.database.ThreadDatabase
|
import org.thoughtcrime.securesms.database.ThreadDatabase
|
||||||
import org.thoughtcrime.securesms.database.LokiMessageDatabase
|
import org.thoughtcrime.securesms.database.LokiMessageDatabase
|
||||||
import org.thoughtcrime.securesms.database.Storage
|
import org.thoughtcrime.securesms.database.Storage
|
||||||
import org.thoughtcrime.securesms.database.model.MessageRecord
|
import org.thoughtcrime.securesms.database.model.MessageRecord
|
||||||
import org.thoughtcrime.securesms.database.model.MmsMessageRecord
|
import org.thoughtcrime.securesms.database.model.MmsMessageRecord
|
||||||
|
import org.thoughtcrime.securesms.dependencies.ConfigFactory
|
||||||
import org.thoughtcrime.securesms.groups.OpenGroupManager
|
import org.thoughtcrime.securesms.groups.OpenGroupManager
|
||||||
import org.thoughtcrime.securesms.mms.AudioSlide
|
import org.thoughtcrime.securesms.mms.AudioSlide
|
||||||
import org.thoughtcrime.securesms.repository.ConversationRepository
|
import org.thoughtcrime.securesms.repository.ConversationRepository
|
||||||
@ -61,7 +62,9 @@ class ConversationViewModel(
|
|||||||
private val groupDb: GroupDatabase,
|
private val groupDb: GroupDatabase,
|
||||||
private val threadDb: ThreadDatabase,
|
private val threadDb: ThreadDatabase,
|
||||||
private val lokiMessageDb: LokiMessageDatabase,
|
private val lokiMessageDb: LokiMessageDatabase,
|
||||||
private val textSecurePreferences: TextSecurePreferences
|
private val textSecurePreferences: TextSecurePreferences,
|
||||||
|
private val configFactory: ConfigFactory,
|
||||||
|
private val groupManagerV2: GroupManagerV2,
|
||||||
) : ViewModel() {
|
) : ViewModel() {
|
||||||
|
|
||||||
val showSendAfterApprovalText: Boolean
|
val showSendAfterApprovalText: Boolean
|
||||||
@ -225,7 +228,7 @@ class ConversationViewModel(
|
|||||||
*/
|
*/
|
||||||
private fun shouldShowInput(recipient: Recipient?): Boolean {
|
private fun shouldShowInput(recipient: Recipient?): Boolean {
|
||||||
return when {
|
return when {
|
||||||
recipient?.isClosedGroupV2Recipient == true -> !repository.isKicked(recipient)
|
recipient?.isClosedGroupV2Recipient == true -> !repository.isGroupReadOnly(recipient)
|
||||||
recipient?.isLegacyClosedGroupRecipient == true -> {
|
recipient?.isLegacyClosedGroupRecipient == true -> {
|
||||||
groupDb.getGroup(recipient.address.toGroupString()).orNull()?.isActive == true
|
groupDb.getGroup(recipient.address.toGroupString()).orNull()?.isActive == true
|
||||||
}
|
}
|
||||||
@ -872,6 +875,37 @@ class ConversationViewModel(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun onOptionItemSelected(
|
||||||
|
// This must be the context of the activity as requirement from ConversationMenuHelper
|
||||||
|
context: Context,
|
||||||
|
item: MenuItem
|
||||||
|
): Boolean {
|
||||||
|
val recipient = recipient ?: return false
|
||||||
|
|
||||||
|
val inProgress = ConversationMenuHelper.onOptionItemSelected(
|
||||||
|
context = context,
|
||||||
|
item = item,
|
||||||
|
thread = recipient,
|
||||||
|
threadID = threadId,
|
||||||
|
factory = configFactory,
|
||||||
|
storage = storage,
|
||||||
|
groupManager = groupManagerV2,
|
||||||
|
)
|
||||||
|
|
||||||
|
if (inProgress != null) {
|
||||||
|
viewModelScope.launch {
|
||||||
|
_uiState.update { it.copy(showLoader = true) }
|
||||||
|
try {
|
||||||
|
inProgress.receive()
|
||||||
|
} finally {
|
||||||
|
_uiState.update { it.copy(showLoader = false) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
@dagger.assisted.AssistedFactory
|
@dagger.assisted.AssistedFactory
|
||||||
interface AssistedFactory {
|
interface AssistedFactory {
|
||||||
fun create(threadId: Long, edKeyPair: KeyPair?): Factory
|
fun create(threadId: Long, edKeyPair: KeyPair?): Factory
|
||||||
@ -890,7 +924,9 @@ class ConversationViewModel(
|
|||||||
@ApplicationContext
|
@ApplicationContext
|
||||||
private val context: Context,
|
private val context: Context,
|
||||||
private val lokiMessageDb: LokiMessageDatabase,
|
private val lokiMessageDb: LokiMessageDatabase,
|
||||||
private val textSecurePreferences: TextSecurePreferences
|
private val textSecurePreferences: TextSecurePreferences,
|
||||||
|
private val configFactory: ConfigFactory,
|
||||||
|
private val groupManagerV2: GroupManagerV2,
|
||||||
) : ViewModelProvider.Factory {
|
) : ViewModelProvider.Factory {
|
||||||
|
|
||||||
override fun <T : ViewModel> create(modelClass: Class<T>): T {
|
override fun <T : ViewModel> create(modelClass: Class<T>): T {
|
||||||
@ -904,7 +940,9 @@ class ConversationViewModel(
|
|||||||
groupDb = groupDb,
|
groupDb = groupDb,
|
||||||
threadDb = threadDb,
|
threadDb = threadDb,
|
||||||
lokiMessageDb = lokiMessageDb,
|
lokiMessageDb = lokiMessageDb,
|
||||||
textSecurePreferences = textSecurePreferences
|
textSecurePreferences = textSecurePreferences,
|
||||||
|
configFactory = configFactory,
|
||||||
|
groupManagerV2 = groupManagerV2,
|
||||||
) as T
|
) as T
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,6 +20,8 @@ import androidx.core.graphics.drawable.IconCompat
|
|||||||
import com.squareup.phrase.Phrase
|
import com.squareup.phrase.Phrase
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.GlobalScope
|
import kotlinx.coroutines.GlobalScope
|
||||||
|
import kotlinx.coroutines.channels.Channel
|
||||||
|
import kotlinx.coroutines.channels.ReceiveChannel
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
@ -156,6 +158,12 @@ object ConversationMenuHelper {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle the selected option
|
||||||
|
*
|
||||||
|
* @return An asynchronous channel that can be used to wait for the action to complete. Null if
|
||||||
|
* the action does not require waiting.
|
||||||
|
*/
|
||||||
fun onOptionItemSelected(
|
fun onOptionItemSelected(
|
||||||
context: Context,
|
context: Context,
|
||||||
item: MenuItem,
|
item: MenuItem,
|
||||||
@ -164,7 +172,7 @@ object ConversationMenuHelper {
|
|||||||
factory: ConfigFactory,
|
factory: ConfigFactory,
|
||||||
storage: StorageProtocol,
|
storage: StorageProtocol,
|
||||||
groupManager: GroupManagerV2,
|
groupManager: GroupManagerV2,
|
||||||
): Boolean {
|
): ReceiveChannel<Unit>? {
|
||||||
when (item.itemId) {
|
when (item.itemId) {
|
||||||
R.id.menu_view_all_media -> { showAllMedia(context, thread) }
|
R.id.menu_view_all_media -> { showAllMedia(context, thread) }
|
||||||
R.id.menu_search -> { search(context) }
|
R.id.menu_search -> { search(context) }
|
||||||
@ -176,14 +184,15 @@ object ConversationMenuHelper {
|
|||||||
R.id.menu_copy_account_id -> { copyAccountID(context, thread) }
|
R.id.menu_copy_account_id -> { copyAccountID(context, thread) }
|
||||||
R.id.menu_copy_open_group_url -> { copyOpenGroupUrl(context, thread) }
|
R.id.menu_copy_open_group_url -> { copyOpenGroupUrl(context, thread) }
|
||||||
R.id.menu_edit_group -> { editClosedGroup(context, thread) }
|
R.id.menu_edit_group -> { editClosedGroup(context, thread) }
|
||||||
R.id.menu_leave_group -> { leaveClosedGroup(context, thread, threadID, factory, storage, groupManager) }
|
R.id.menu_leave_group -> { return leaveClosedGroup(context, thread, threadID, factory, storage, groupManager) }
|
||||||
R.id.menu_invite_to_open_group -> { inviteContacts(context, thread) }
|
R.id.menu_invite_to_open_group -> { inviteContacts(context, thread) }
|
||||||
R.id.menu_unmute_notifications -> { unmute(context, thread) }
|
R.id.menu_unmute_notifications -> { unmute(context, thread) }
|
||||||
R.id.menu_mute_notifications -> { mute(context, thread) }
|
R.id.menu_mute_notifications -> { mute(context, thread) }
|
||||||
R.id.menu_notification_settings -> { setNotifyType(context, thread) }
|
R.id.menu_notification_settings -> { setNotifyType(context, thread) }
|
||||||
R.id.menu_call -> { call(context, thread) }
|
R.id.menu_call -> { call(context, thread) }
|
||||||
}
|
}
|
||||||
return true
|
|
||||||
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun showAllMedia(context: Context, thread: Recipient) {
|
private fun showAllMedia(context: Context, thread: Recipient) {
|
||||||
@ -330,7 +339,7 @@ object ConversationMenuHelper {
|
|||||||
configFactory: ConfigFactory,
|
configFactory: ConfigFactory,
|
||||||
storage: StorageProtocol,
|
storage: StorageProtocol,
|
||||||
groupManager: GroupManagerV2,
|
groupManager: GroupManagerV2,
|
||||||
) {
|
): ReceiveChannel<Unit>? {
|
||||||
when {
|
when {
|
||||||
thread.isLegacyClosedGroupRecipient -> {
|
thread.isLegacyClosedGroupRecipient -> {
|
||||||
val group = DatabaseComponent.get(context).groupDatabase().getGroup(thread.address.toGroupString()).orNull()
|
val group = DatabaseComponent.get(context).groupDatabase().getGroup(thread.address.toGroupString()).orNull()
|
||||||
@ -357,11 +366,13 @@ object ConversationMenuHelper {
|
|||||||
|
|
||||||
thread.isClosedGroupV2Recipient -> {
|
thread.isClosedGroupV2Recipient -> {
|
||||||
val accountId = AccountId(thread.address.serialize())
|
val accountId = AccountId(thread.address.serialize())
|
||||||
val group = configFactory.withUserConfigs { it.userGroups.getClosedGroup(accountId.hexString) } ?: return
|
val group = configFactory.withUserConfigs { it.userGroups.getClosedGroup(accountId.hexString) } ?: return null
|
||||||
val name = configFactory.withGroupConfigs(accountId) {
|
val name = configFactory.withGroupConfigs(accountId) {
|
||||||
it.groupInfo.getName()
|
it.groupInfo.getName()
|
||||||
} ?: group.name
|
} ?: group.name
|
||||||
|
|
||||||
|
val channel = Channel<Unit>()
|
||||||
|
|
||||||
confirmAndLeaveClosedGroup(
|
confirmAndLeaveClosedGroup(
|
||||||
context = context,
|
context = context,
|
||||||
groupName = name,
|
groupName = name,
|
||||||
@ -369,11 +380,19 @@ object ConversationMenuHelper {
|
|||||||
threadID = threadID,
|
threadID = threadID,
|
||||||
storage = storage,
|
storage = storage,
|
||||||
doLeave = {
|
doLeave = {
|
||||||
|
try {
|
||||||
groupManager.leaveGroup(accountId, true)
|
groupManager.leaveGroup(accountId, true)
|
||||||
|
} finally {
|
||||||
|
channel.send(Unit)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
return channel
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun confirmAndLeaveClosedGroup(
|
private fun confirmAndLeaveClosedGroup(
|
||||||
|
@ -365,7 +365,9 @@ class ConfigFactory @Inject constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Unit to configs.dumpIfNeeded(clock)
|
configs.dumpIfNeeded(clock)
|
||||||
|
|
||||||
|
Unit to true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -388,12 +388,32 @@ class GroupManagerV2Impl @Inject constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun leaveGroup(group: AccountId, deleteOnLeave: Boolean) {
|
override suspend fun leaveGroup(groupId: AccountId, deleteOnLeave: Boolean) {
|
||||||
val canSendGroupMessage = configFactory.getClosedGroup(group)?.kicked == false
|
val group = configFactory.getClosedGroup(groupId)
|
||||||
|
|
||||||
if (canSendGroupMessage) {
|
// Only send the left/left notification group message when we are not kicked and we are not the only admin (only admin has a special treatment)
|
||||||
val destination = Destination.ClosedGroup(group.hexString)
|
val weAreTheOnlyAdmin = configFactory.withGroupConfigs(groupId) { config ->
|
||||||
|
val allMembers = config.groupMembers.all()
|
||||||
|
allMembers.count { it.admin } == 1 &&
|
||||||
|
allMembers.first { it.admin }.sessionId == storage.getUserPublicKey()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (group?.kicked == false) {
|
||||||
|
val destination = Destination.ClosedGroup(groupId.hexString)
|
||||||
|
|
||||||
|
// Always send a "XXX left" message to the group if we can
|
||||||
|
MessageSender.send(
|
||||||
|
GroupUpdated(
|
||||||
|
GroupUpdateMessage.newBuilder()
|
||||||
|
.setMemberLeftNotificationMessage(DataMessage.GroupUpdateMemberLeftNotificationMessage.getDefaultInstance())
|
||||||
|
.build()
|
||||||
|
),
|
||||||
|
destination,
|
||||||
|
isSyncMessage = false
|
||||||
|
)
|
||||||
|
|
||||||
|
// If we are not the only admin, send a left message for other admin to handle the member removal
|
||||||
|
if (!weAreTheOnlyAdmin) {
|
||||||
MessageSender.send(
|
MessageSender.send(
|
||||||
GroupUpdated(
|
GroupUpdated(
|
||||||
GroupUpdateMessage.newBuilder()
|
GroupUpdateMessage.newBuilder()
|
||||||
@ -403,23 +423,27 @@ class GroupManagerV2Impl @Inject constructor(
|
|||||||
destination,
|
destination,
|
||||||
isSyncMessage = false
|
isSyncMessage = false
|
||||||
).await()
|
).await()
|
||||||
|
}
|
||||||
MessageSender.send(
|
|
||||||
GroupUpdated(
|
|
||||||
GroupUpdateMessage.newBuilder()
|
|
||||||
.setMemberLeftNotificationMessage(DataMessage.GroupUpdateMemberLeftNotificationMessage.getDefaultInstance())
|
|
||||||
.build()
|
|
||||||
),
|
|
||||||
destination,
|
|
||||||
isSyncMessage = false
|
|
||||||
).await()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pollerFactory.pollerFor(group)?.stop()
|
// If we are the only admin, leaving this group will destroy the group
|
||||||
|
if (weAreTheOnlyAdmin) {
|
||||||
|
configFactory.withMutableGroupConfigs(groupId) { configs ->
|
||||||
|
configs.groupInfo.destroyGroup()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Must wait until the config is pushed, otherwise if we go through the rest
|
||||||
|
// of the code it will destroy the conversation, destroying the necessary configs
|
||||||
|
// along the way, we won't be able to push the "destroyed" state anymore.
|
||||||
|
configFactory.waitUntilGroupConfigsPushed(groupId)
|
||||||
|
}
|
||||||
|
|
||||||
|
pollerFactory.pollerFor(groupId)?.stop()
|
||||||
|
|
||||||
if (deleteOnLeave) {
|
if (deleteOnLeave) {
|
||||||
storage.getThreadId(Address.fromSerialized(group.hexString))
|
storage.getThreadId(Address.fromSerialized(groupId.hexString))
|
||||||
?.let(storage::deleteConversation)
|
?.let(storage::deleteConversation)
|
||||||
configFactory.removeGroup(group)
|
configFactory.removeGroup(groupId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,6 +28,7 @@ import org.session.libsession.snode.utilities.await
|
|||||||
import org.session.libsession.utilities.Address
|
import org.session.libsession.utilities.Address
|
||||||
import org.session.libsession.utilities.GroupUtil
|
import org.session.libsession.utilities.GroupUtil
|
||||||
import org.session.libsession.utilities.TextSecurePreferences
|
import org.session.libsession.utilities.TextSecurePreferences
|
||||||
|
import org.session.libsession.utilities.getClosedGroup
|
||||||
import org.session.libsession.utilities.recipients.Recipient
|
import org.session.libsession.utilities.recipients.Recipient
|
||||||
import org.session.libsignal.utilities.AccountId
|
import org.session.libsignal.utilities.AccountId
|
||||||
import org.thoughtcrime.securesms.database.DatabaseContentProviders
|
import org.thoughtcrime.securesms.database.DatabaseContentProviders
|
||||||
@ -59,7 +60,7 @@ interface ConversationRepository {
|
|||||||
fun deleteMessages(messages: Set<MessageRecord>, threadId: Long)
|
fun deleteMessages(messages: Set<MessageRecord>, threadId: Long)
|
||||||
fun deleteAllLocalMessagesInThreadFromSenderOfMessage(messageRecord: MessageRecord)
|
fun deleteAllLocalMessagesInThreadFromSenderOfMessage(messageRecord: MessageRecord)
|
||||||
fun setApproved(recipient: Recipient, isApproved: Boolean)
|
fun setApproved(recipient: Recipient, isApproved: Boolean)
|
||||||
fun isKicked(recipient: Recipient): Boolean
|
fun isGroupReadOnly(recipient: Recipient): Boolean
|
||||||
|
|
||||||
suspend fun deleteCommunityMessagesRemotely(threadId: Long, messages: Set<MessageRecord>)
|
suspend fun deleteCommunityMessagesRemotely(threadId: Long, messages: Set<MessageRecord>)
|
||||||
suspend fun delete1on1MessagesRemotely(
|
suspend fun delete1on1MessagesRemotely(
|
||||||
@ -170,15 +171,16 @@ class DefaultConversationRepository @Inject constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun isKicked(recipient: Recipient): Boolean {
|
override fun isGroupReadOnly(recipient: Recipient): Boolean {
|
||||||
// For now, we only know care we are kicked for a groups v2 recipient
|
// We only care about group v2 recipient
|
||||||
if (!recipient.isClosedGroupV2Recipient) {
|
if (!recipient.isClosedGroupV2Recipient) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val groupId = recipient.address.serialize()
|
||||||
return configFactory.withUserConfigs {
|
return configFactory.withUserConfigs {
|
||||||
it.userGroups.getClosedGroup(recipient.address.serialize())?.kicked == true
|
it.userGroups.getClosedGroup(groupId)?.kicked == true
|
||||||
}
|
} || configFactory.withGroupConfigs(AccountId(groupId)) { it.groupInfo.isDestroyed() }
|
||||||
}
|
}
|
||||||
|
|
||||||
// This assumes that recipient.isContactRecipient is true
|
// This assumes that recipient.isContactRecipient is true
|
||||||
|
@ -44,7 +44,7 @@ interface GroupManagerV2 {
|
|||||||
|
|
||||||
suspend fun handleMemberLeft(message: GroupUpdated, group: AccountId)
|
suspend fun handleMemberLeft(message: GroupUpdated, group: AccountId)
|
||||||
|
|
||||||
suspend fun leaveGroup(group: AccountId, deleteOnLeave: Boolean)
|
suspend fun leaveGroup(groupId: AccountId, deleteOnLeave: Boolean)
|
||||||
|
|
||||||
suspend fun promoteMember(group: AccountId, members: List<AccountId>)
|
suspend fun promoteMember(group: AccountId, members: List<AccountId>)
|
||||||
|
|
||||||
|
@ -120,7 +120,6 @@ class JobQueue : JobDelegate {
|
|||||||
is NotifyPNServerJob,
|
is NotifyPNServerJob,
|
||||||
is AttachmentUploadJob,
|
is AttachmentUploadJob,
|
||||||
is GroupLeavingJob,
|
is GroupLeavingJob,
|
||||||
is LibSessionGroupLeavingJob,
|
|
||||||
is MessageSendJob -> {
|
is MessageSendJob -> {
|
||||||
txQueue.send(job)
|
txQueue.send(job)
|
||||||
}
|
}
|
||||||
@ -226,7 +225,6 @@ class JobQueue : JobDelegate {
|
|||||||
RetrieveProfileAvatarJob.KEY,
|
RetrieveProfileAvatarJob.KEY,
|
||||||
GroupLeavingJob.KEY,
|
GroupLeavingJob.KEY,
|
||||||
InviteContactsJob.KEY,
|
InviteContactsJob.KEY,
|
||||||
LibSessionGroupLeavingJob.KEY
|
|
||||||
)
|
)
|
||||||
allJobTypes.forEach { type ->
|
allJobTypes.forEach { type ->
|
||||||
resumePendingJobs(type)
|
resumePendingJobs(type)
|
||||||
|
@ -1,67 +0,0 @@
|
|||||||
package org.session.libsession.messaging.jobs
|
|
||||||
|
|
||||||
import org.session.libsession.messaging.MessagingModuleConfiguration
|
|
||||||
import org.session.libsession.messaging.utilities.Data
|
|
||||||
import org.session.libsession.messaging.utilities.UpdateMessageData
|
|
||||||
import org.session.libsignal.utilities.AccountId
|
|
||||||
|
|
||||||
class LibSessionGroupLeavingJob(val accountId: AccountId, val deleteOnLeave: Boolean): Job {
|
|
||||||
|
|
||||||
|
|
||||||
override var delegate: JobDelegate? = null
|
|
||||||
override var id: String? = null
|
|
||||||
override var failureCount: Int = 0
|
|
||||||
override val maxFailureCount: Int = 4
|
|
||||||
|
|
||||||
override suspend fun execute(dispatcherName: String) {
|
|
||||||
val storage = MessagingModuleConfiguration.shared.storage
|
|
||||||
// start leaving
|
|
||||||
// create message ID with leaving state
|
|
||||||
val messageId = storage.insertGroupInfoLeaving(accountId) ?: run {
|
|
||||||
delegate?.handleJobFailedPermanently(
|
|
||||||
this,
|
|
||||||
dispatcherName,
|
|
||||||
Exception("Couldn't insert GroupInfoLeaving message in leaving group job")
|
|
||||||
)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// do actual group leave request
|
|
||||||
|
|
||||||
// on success
|
|
||||||
val leaveGroup = kotlin.runCatching {
|
|
||||||
MessagingModuleConfiguration.shared.groupManagerV2.leaveGroup(accountId, deleteOnLeave)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (leaveGroup.isSuccess) {
|
|
||||||
// message is already deleted, succeed
|
|
||||||
delegate?.handleJobSucceeded(this, dispatcherName)
|
|
||||||
} else {
|
|
||||||
// Error leaving group, update the info message
|
|
||||||
storage.updateGroupInfoChange(messageId, UpdateMessageData.Kind.GroupErrorQuit)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun serialize(): Data =
|
|
||||||
Data.Builder()
|
|
||||||
.putString(SESSION_ID_KEY, accountId.hexString)
|
|
||||||
.putBoolean(DELETE_ON_LEAVE_KEY, deleteOnLeave)
|
|
||||||
.build()
|
|
||||||
|
|
||||||
class Factory : Job.Factory<LibSessionGroupLeavingJob> {
|
|
||||||
override fun create(data: Data): LibSessionGroupLeavingJob {
|
|
||||||
return LibSessionGroupLeavingJob(
|
|
||||||
AccountId(data.getString(SESSION_ID_KEY)),
|
|
||||||
data.getBoolean(DELETE_ON_LEAVE_KEY)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getFactoryKey(): String = KEY
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
const val KEY = "LibSessionGroupLeavingJob"
|
|
||||||
private const val SESSION_ID_KEY = "SessionId"
|
|
||||||
private const val DELETE_ON_LEAVE_KEY = "DeleteOnLeave"
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user