diff --git a/src/org/thoughtcrime/securesms/groups/GroupManager.java b/src/org/thoughtcrime/securesms/groups/GroupManager.java index 9ea420da54..fa0fb72a63 100644 --- a/src/org/thoughtcrime/securesms/groups/GroupManager.java +++ b/src/org/thoughtcrime/securesms/groups/GroupManager.java @@ -3,6 +3,7 @@ package org.thoughtcrime.securesms.groups; import android.content.Context; import android.graphics.Bitmap; import android.net.Uri; + import androidx.annotation.NonNull; import androidx.annotation.Nullable; @@ -23,7 +24,6 @@ import org.thoughtcrime.securesms.util.BitmapUtil; import org.thoughtcrime.securesms.util.GroupUtil; import org.thoughtcrime.securesms.util.MediaUtil; import org.thoughtcrime.securesms.util.TextSecurePreferences; -import org.whispersystems.libsignal.util.guava.Optional; import org.whispersystems.signalservice.api.util.InvalidNumberException; import org.whispersystems.signalservice.internal.push.SignalServiceProtos.GroupContext; @@ -134,8 +134,8 @@ public class GroupManager { return new GroupActionResult(groupRecipient, threadID); } - public static boolean deleteGroup(@NonNull String groupId, - @NonNull Context context) + public static boolean deleteGroup(@NonNull String groupId, + @NonNull Context context) { final GroupDatabase groupDatabase = DatabaseFactory.getGroupDatabase(context); final ThreadDatabase threadDatabase = DatabaseFactory.getThreadDatabase(context); diff --git a/src/org/thoughtcrime/securesms/loki/activities/HomeActivity.kt b/src/org/thoughtcrime/securesms/loki/activities/HomeActivity.kt index e5f84a673e..f6e28336b4 100644 --- a/src/org/thoughtcrime/securesms/loki/activities/HomeActivity.kt +++ b/src/org/thoughtcrime/securesms/loki/activities/HomeActivity.kt @@ -9,7 +9,6 @@ import android.database.Cursor import android.net.Uri import android.os.AsyncTask import android.os.Bundle -import android.os.Handler import android.text.Spannable import android.text.SpannableString import android.text.style.ForegroundColorSpan @@ -18,11 +17,15 @@ import android.view.View import android.widget.RelativeLayout import android.widget.Toast import androidx.lifecycle.Observer +import androidx.lifecycle.lifecycleScope import androidx.loader.app.LoaderManager import androidx.loader.content.Loader import androidx.localbroadcastmanager.content.LocalBroadcastManager import androidx.recyclerview.widget.LinearLayoutManager import kotlinx.android.synthetic.main.activity_home.* +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext import network.loki.messenger.R import org.thoughtcrime.securesms.ApplicationContext import org.thoughtcrime.securesms.PassphraseRequiredActionBarActivity @@ -71,24 +74,6 @@ class HomeActivity : PassphraseRequiredActionBarActivity, ConversationClickListe override fun onCreate(savedInstanceState: Bundle?, isReady: Boolean) { super.onCreate(savedInstanceState, isReady) - // Process any outstanding deletes - val threadDatabase = DatabaseFactory.getThreadDatabase(this) - val archivedConversationCount = threadDatabase.archivedConversationListCount - if (archivedConversationCount > 0) { - val archivedConversations = threadDatabase.archivedConversationList - archivedConversations.moveToFirst() - fun deleteThreadAtCurrentPosition() { - val threadID = archivedConversations.getLong(archivedConversations.getColumnIndex(ThreadDatabase.ID)) - AsyncTask.execute { - threadDatabase.deleteConversation(threadID) - (applicationContext as ApplicationContext).messageNotifier.updateNotification(this) - } - } - deleteThreadAtCurrentPosition() - while (archivedConversations.moveToNext()) { - deleteThreadAtCurrentPosition() - } - } // Double check that the long poller is up (applicationContext as ApplicationContext).startPollingIfNeeded() // Set content view @@ -341,58 +326,56 @@ class HomeActivity : PassphraseRequiredActionBarActivity, ConversationClickListe val threadID = thread.threadId val recipient = thread.recipient val threadDB = DatabaseFactory.getThreadDatabase(this) - val deleteThread = Runnable { - //TODO Move open group related logic to OpenGroupUtilities / PublicChatManager / GroupManager - AsyncTask.execute { - val publicChat = DatabaseFactory.getLokiThreadDatabase(this@HomeActivity).getPublicChat(threadID) - if (publicChat != null) { - val apiDB = DatabaseFactory.getLokiAPIDatabase(this@HomeActivity) - apiDB.removeLastMessageServerID(publicChat.channel, publicChat.server) - apiDB.removeLastDeletionServerID(publicChat.channel, publicChat.server) - apiDB.clearOpenGroupProfilePictureURL(publicChat.channel, publicChat.server) - ApplicationContext.getInstance(this@HomeActivity).publicChatAPI!!.leave(publicChat.channel, publicChat.server) - - //FIXME Group deletion should be synchronized with the related thread deletion. - val groupId = threadDB.getRecipientForThreadId(threadID)!!.address.serialize() - GroupManager.deleteGroup(groupId, this@HomeActivity) - } - threadDB.deleteConversation(threadID) - ApplicationContext.getInstance(this@HomeActivity).messageNotifier.updateNotification(this@HomeActivity) - } - } val dialogMessage = if (recipient.isGroupRecipient) R.string.activity_home_leave_group_dialog_message else R.string.activity_home_delete_conversation_dialog_message val dialog = AlertDialog.Builder(this) dialog.setMessage(dialogMessage) - dialog.setPositiveButton(R.string.yes) { _, _ -> + dialog.setPositiveButton(R.string.yes) { _, _ -> lifecycleScope.launch(Dispatchers.Main) { + val context = this@HomeActivity as Context + val isClosedGroup = recipient.address.isClosedGroup // Send a leave group message if this is an active closed group - if (isClosedGroup && DatabaseFactory.getGroupDatabase(this).isActive(recipient.address.toGroupString())) { + if (isClosedGroup && DatabaseFactory.getGroupDatabase(context).isActive(recipient.address.toGroupString())) { var isSSKBasedClosedGroup: Boolean var groupPublicKey: String? try { groupPublicKey = ClosedGroupsProtocol.doubleDecodeGroupID(recipient.address.toString()).toHexString() - isSSKBasedClosedGroup = DatabaseFactory.getSSKDatabase(this).isSSKBasedClosedGroup(groupPublicKey) + isSSKBasedClosedGroup = DatabaseFactory.getSSKDatabase(context).isSSKBasedClosedGroup(groupPublicKey) } catch (e: IOException) { groupPublicKey = null isSSKBasedClosedGroup = false } if (isSSKBasedClosedGroup) { - ClosedGroupsProtocol.leave(this, groupPublicKey!!) - } else if (!ClosedGroupsProtocol.leaveLegacyGroup(this, recipient)) { - Toast.makeText(this, R.string.activity_home_leaving_group_failed_message, Toast.LENGTH_LONG).show() - return@setPositiveButton + ClosedGroupsProtocol.leave(context, groupPublicKey!!) + } else if (!ClosedGroupsProtocol.leaveLegacyGroup(context, recipient)) { + Toast.makeText(context, R.string.activity_home_leaving_group_failed_message, Toast.LENGTH_LONG).show() + return@launch + } + } + + withContext(Dispatchers.IO) { + val publicChat = DatabaseFactory.getLokiThreadDatabase(context).getPublicChat(threadID) + //TODO Move open group related logic to OpenGroupUtilities / PublicChatManager / GroupManager + if (publicChat != null) { + val apiDB = DatabaseFactory.getLokiAPIDatabase(context) + apiDB.removeLastMessageServerID(publicChat.channel, publicChat.server) + apiDB.removeLastDeletionServerID(publicChat.channel, publicChat.server) + apiDB.clearOpenGroupProfilePictureURL(publicChat.channel, publicChat.server) + + ApplicationContext.getInstance(context).publicChatAPI!! + .leave(publicChat.channel, publicChat.server) + + ApplicationContext.getInstance(context).publicChatManager + .removeChat(publicChat.server, publicChat.channel) + } else { + threadDB.deleteConversation(threadID) } + ApplicationContext.getInstance(context).messageNotifier.updateNotification(context) } - // Archive the conversation and then delete it after 10 seconds (the case where the - // app was closed before the conversation could be deleted is handled in onCreate) - threadDB.archiveConversation(threadID) - val delay = if (isClosedGroup) 10000L else 1000L - val handler = Handler() - handler.postDelayed(deleteThread, delay) + // Notify the user val toastMessage = if (recipient.isGroupRecipient) R.string.MessageRecord_left_group else R.string.activity_home_conversation_deleted_message - Toast.makeText(this, toastMessage, Toast.LENGTH_LONG).show() - } + Toast.makeText(context, toastMessage, Toast.LENGTH_LONG).show() + }} dialog.setNegativeButton(R.string.no) { _, _ -> // Do nothing } diff --git a/src/org/thoughtcrime/securesms/loki/api/PublicChatManager.kt b/src/org/thoughtcrime/securesms/loki/api/PublicChatManager.kt index a4281704e5..ca7352ec8d 100644 --- a/src/org/thoughtcrime/securesms/loki/api/PublicChatManager.kt +++ b/src/org/thoughtcrime/securesms/loki/api/PublicChatManager.kt @@ -5,9 +5,6 @@ import android.database.ContentObserver import android.graphics.Bitmap import android.text.TextUtils import androidx.annotation.WorkerThread -import nl.komponents.kovenant.Promise -import nl.komponents.kovenant.functional.bind -import nl.komponents.kovenant.functional.map import org.thoughtcrime.securesms.ApplicationContext import org.thoughtcrime.securesms.database.DatabaseContentProviders import org.thoughtcrime.securesms.database.DatabaseFactory @@ -96,11 +93,21 @@ class PublicChatManager(private val context: Context) { ApplicationContext.getInstance(context).publicChatAPI?.setDisplayName(displayName, server) } // Start polling - Util.runOnMain{ startPollersIfNeeded() } + Util.runOnMain { startPollersIfNeeded() } return chat } + public fun removeChat(server: String, channel: Long) { + val threadDB = DatabaseFactory.getThreadDatabase(context) + val groupId = PublicChat.getId(channel, server) + val threadId = GroupManager.getOpenGroupThreadID(groupId, context) + val groupAddress = threadDB.getRecipientForThreadId(threadId)!!.address.serialize() + GroupManager.deleteGroup(groupAddress, context) + + Util.runOnMain { startPollersIfNeeded() } + } + private fun refreshChatsAndPollers() { val chatsInDB = DatabaseFactory.getLokiThreadDatabase(context).getAllPublicChats() val removedChatThreadIds = chats.keys.filter { !chatsInDB.keys.contains(it) }