Show a loader while the group is being created

This commit is contained in:
nielsandriesse 2020-09-02 11:47:54 +10:00
parent 146df2c5ef
commit 2732b95940
3 changed files with 75 additions and 40 deletions

View File

@ -3,7 +3,8 @@
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:background="@drawable/default_session_background" > xmlns:app="http://schemas.android.com/apk/res-auto"
android:background="@drawable/default_session_background">
<LinearLayout <LinearLayout
android:id="@+id/mainContentContainer" android:id="@+id/mainContentContainer"
@ -59,4 +60,22 @@
</LinearLayout> </LinearLayout>
<RelativeLayout
android:id="@+id/loader"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#A4000000"
android:visibility="gone"
android:alpha="0">
<com.github.ybq.android.spinkit.SpinKitView
style="@style/SpinKitView.Large.ThreeBounce"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:layout_centerInParent="true"
app:SpinKit_Color="@color/text" />
</RelativeLayout>
</RelativeLayout> </RelativeLayout>

View File

@ -15,6 +15,7 @@ import android.widget.Toast
import kotlinx.android.synthetic.main.activity_create_closed_group.* import kotlinx.android.synthetic.main.activity_create_closed_group.*
import kotlinx.android.synthetic.main.activity_linked_devices.recyclerView import kotlinx.android.synthetic.main.activity_linked_devices.recyclerView
import network.loki.messenger.R import network.loki.messenger.R
import nl.komponents.kovenant.ui.successUi
import org.thoughtcrime.securesms.PassphraseRequiredActionBarActivity import org.thoughtcrime.securesms.PassphraseRequiredActionBarActivity
import org.thoughtcrime.securesms.conversation.ConversationActivity import org.thoughtcrime.securesms.conversation.ConversationActivity
import org.thoughtcrime.securesms.database.Address import org.thoughtcrime.securesms.database.Address
@ -22,6 +23,8 @@ import org.thoughtcrime.securesms.database.DatabaseFactory
import org.thoughtcrime.securesms.database.ThreadDatabase import org.thoughtcrime.securesms.database.ThreadDatabase
import org.thoughtcrime.securesms.groups.GroupManager import org.thoughtcrime.securesms.groups.GroupManager
import org.thoughtcrime.securesms.loki.protocol.ClosedGroupsProtocol import org.thoughtcrime.securesms.loki.protocol.ClosedGroupsProtocol
import org.thoughtcrime.securesms.loki.utilities.fadeIn
import org.thoughtcrime.securesms.loki.utilities.fadeOut
import org.thoughtcrime.securesms.mms.GlideApp import org.thoughtcrime.securesms.mms.GlideApp
import org.thoughtcrime.securesms.recipients.Recipient import org.thoughtcrime.securesms.recipients.Recipient
import org.thoughtcrime.securesms.util.TextSecurePreferences import org.thoughtcrime.securesms.util.TextSecurePreferences
@ -122,9 +125,15 @@ class CreateClosedGroupActivity : PassphraseRequiredActionBarActivity(), LoaderM
return Toast.makeText(this, R.string.activity_create_closed_group_too_many_group_members_error, Toast.LENGTH_LONG).show() return Toast.makeText(this, R.string.activity_create_closed_group_too_many_group_members_error, Toast.LENGTH_LONG).show()
} }
val userPublicKey = TextSecurePreferences.getLocalNumber(this) val userPublicKey = TextSecurePreferences.getLocalNumber(this)
val groupID = ClosedGroupsProtocol.createClosedGroup(this, name.toString(), selectedMembers + setOf( userPublicKey )) loader.fadeIn()
val threadID = DatabaseFactory.getThreadDatabase(this).getThreadIdFor(Recipient.from(this, Address.fromSerialized(groupID), false)) ClosedGroupsProtocol.createClosedGroup(this, name.toString(), selectedMembers + setOf( userPublicKey )).successUi { groupID ->
openConversationActivity(this, threadID, Recipient.from(this, Address.fromSerialized(groupID), false)) loader.fadeOut()
val threadID = DatabaseFactory.getThreadDatabase(this).getThreadIdFor(Recipient.from(this, Address.fromSerialized(groupID), false))
if (!isFinishing) {
openConversationActivity(this, threadID, Recipient.from(this, Address.fromSerialized(groupID), false))
finish()
}
}
} }
private fun createLegacyClosedGroup() { private fun createLegacyClosedGroup() {

View File

@ -3,6 +3,8 @@ package org.thoughtcrime.securesms.loki.protocol
import android.content.Context import android.content.Context
import android.util.Log import android.util.Log
import com.google.protobuf.ByteString import com.google.protobuf.ByteString
import nl.komponents.kovenant.Promise
import nl.komponents.kovenant.deferred
import org.thoughtcrime.securesms.ApplicationContext import org.thoughtcrime.securesms.ApplicationContext
import org.thoughtcrime.securesms.database.Address import org.thoughtcrime.securesms.database.Address
import org.thoughtcrime.securesms.database.DatabaseFactory import org.thoughtcrime.securesms.database.DatabaseFactory
@ -34,43 +36,48 @@ object ClosedGroupsProtocol {
val isSharedSenderKeysEnabled = false val isSharedSenderKeysEnabled = false
val groupSizeLimit = 10 val groupSizeLimit = 10
public fun createClosedGroup(context: Context, name: String, members: Collection<String>): String { public fun createClosedGroup(context: Context, name: String, members: Collection<String>): Promise<String, Exception> {
// Prepare val deferred = deferred<String, Exception>()
val userPublicKey = TextSecurePreferences.getLocalNumber(context) Thread {
// Generate a key pair for the group // Prepare
val groupKeyPair = Curve.generateKeyPair() val userPublicKey = TextSecurePreferences.getLocalNumber(context)
val groupPublicKey = groupKeyPair.hexEncodedPublicKey // Includes the "05" prefix // Generate a key pair for the group
val membersAsData = members.map { Hex.fromStringCondensed(it) } val groupKeyPair = Curve.generateKeyPair()
// Create ratchets for all members val groupPublicKey = groupKeyPair.hexEncodedPublicKey // Includes the "05" prefix
val senderKeys: List<ClosedGroupSenderKey> = members.map { publicKey -> val membersAsData = members.map { Hex.fromStringCondensed(it) }
val ratchet = SharedSenderKeysImplementation.shared.generateRatchet(groupPublicKey, publicKey) // Create ratchets for all members
ClosedGroupSenderKey(Hex.fromStringCondensed(ratchet.chainKey), ratchet.keyIndex, Hex.fromStringCondensed(publicKey)) val senderKeys: List<ClosedGroupSenderKey> = members.map { publicKey ->
} val ratchet = SharedSenderKeysImplementation.shared.generateRatchet(groupPublicKey, publicKey)
// Create the group ClosedGroupSenderKey(Hex.fromStringCondensed(ratchet.chainKey), ratchet.keyIndex, Hex.fromStringCondensed(publicKey))
val groupID = doubleEncodeGroupID(groupPublicKey) }
val admins = setOf( userPublicKey ) // Create the group
DatabaseFactory.getGroupDatabase(context).create(groupID, name, LinkedList<Address>(members.map { Address.fromSerialized(it) }), val groupID = doubleEncodeGroupID(groupPublicKey)
null, null, LinkedList<Address>(admins.map { Address.fromSerialized(it) })) val admins = setOf( userPublicKey )
DatabaseFactory.getRecipientDatabase(context).setProfileSharing(Recipient.from(context, Address.fromSerialized(groupID), false), true) DatabaseFactory.getGroupDatabase(context).create(groupID, name, LinkedList<Address>(members.map { Address.fromSerialized(it) }),
// Establish sessions if needed null, null, LinkedList<Address>(admins.map { Address.fromSerialized(it) }))
establishSessionsWithMembersIfNeeded(context, members) DatabaseFactory.getRecipientDatabase(context).setProfileSharing(Recipient.from(context, Address.fromSerialized(groupID), false), true)
// Send a closed group update message to all members using established channels // Establish sessions if needed
val adminsAsData = admins.map { Hex.fromStringCondensed(it) } establishSessionsWithMembersIfNeeded(context, members)
val closedGroupUpdateKind = ClosedGroupUpdateMessageSendJob.Kind.New(Hex.fromStringCondensed(groupPublicKey), name, groupKeyPair.privateKey.serialize(), // Send a closed group update message to all members using established channels
senderKeys, membersAsData, adminsAsData) val adminsAsData = admins.map { Hex.fromStringCondensed(it) }
for (member in members) { val closedGroupUpdateKind = ClosedGroupUpdateMessageSendJob.Kind.New(Hex.fromStringCondensed(groupPublicKey), name, groupKeyPair.privateKey.serialize(),
if (member == userPublicKey) { continue } senderKeys, membersAsData, adminsAsData)
val job = ClosedGroupUpdateMessageSendJob(member, closedGroupUpdateKind) for (member in members) {
ApplicationContext.getInstance(context).jobManager.add(job) if (member == userPublicKey) { continue }
} val job = ClosedGroupUpdateMessageSendJob(member, closedGroupUpdateKind)
// TODO: Wait for the messages to finish sending job.setContext(context)
// Add the group to the user's set of public keys to poll for job.onRun() // Run the job immediately
DatabaseFactory.getSSKDatabase(context).setClosedGroupPrivateKey(groupPublicKey, groupKeyPair.hexEncodedPrivateKey) }
// Notify the user // Add the group to the user's set of public keys to poll for
val threadID = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(Recipient.from(context, Address.fromSerialized(groupID), false)) DatabaseFactory.getSSKDatabase(context).setClosedGroupPrivateKey(groupPublicKey, groupKeyPair.hexEncodedPrivateKey)
insertOutgoingInfoMessage(context, groupID, GroupContext.Type.UPDATE, name, members, admins, threadID) // Notify the user
val threadID = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(Recipient.from(context, Address.fromSerialized(groupID), false))
insertOutgoingInfoMessage(context, groupID, GroupContext.Type.UPDATE, name, members, admins, threadID)
// Fulfill the promise
deferred.resolve(groupID)
}.start()
// Return // Return
return groupID return deferred.promise
} }
@JvmStatic @JvmStatic