mirror of
https://github.com/oxen-io/session-android.git
synced 2025-06-09 13:18:34 +00:00
Show Group V2 invited member dialog explaining invites on new group and add to group.
This commit is contained in:
parent
ae2b6e4d7a
commit
a59e214317
@ -54,17 +54,7 @@ public final class GroupManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@WorkerThread
|
@WorkerThread
|
||||||
public static @NonNull GroupActionResult createGroupV1(@NonNull Context context,
|
public static GroupActionResult updateGroupDetails(@NonNull Context context,
|
||||||
@NonNull Set<Recipient> members,
|
|
||||||
@Nullable byte[] avatar,
|
|
||||||
@Nullable String name,
|
|
||||||
boolean mms)
|
|
||||||
{
|
|
||||||
return GroupManagerV1.createGroup(context, getMemberIds(members), avatar, name, mms);
|
|
||||||
}
|
|
||||||
|
|
||||||
@WorkerThread
|
|
||||||
public static GroupActionResult updateGroup(@NonNull Context context,
|
|
||||||
@NonNull GroupId groupId,
|
@NonNull GroupId groupId,
|
||||||
@Nullable byte[] avatar,
|
@Nullable byte[] avatar,
|
||||||
boolean avatarChanged,
|
boolean avatarChanged,
|
||||||
@ -80,23 +70,15 @@ public final class GroupManager {
|
|||||||
List<Recipient> members = DatabaseFactory.getGroupDatabase(context)
|
List<Recipient> members = DatabaseFactory.getGroupDatabase(context)
|
||||||
.getGroupMembers(groupId, GroupDatabase.MemberSet.FULL_MEMBERS_EXCLUDING_SELF);
|
.getGroupMembers(groupId, GroupDatabase.MemberSet.FULL_MEMBERS_EXCLUDING_SELF);
|
||||||
|
|
||||||
return updateGroup(context, groupId.requireV1(), new HashSet<>(members), avatar, name);
|
Set<RecipientId> recipientIds = getMemberIds(new HashSet<>(members));
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static @Nullable GroupActionResult updateGroup(@NonNull Context context,
|
return GroupManagerV1.updateGroup(context, groupId.requireV1(), recipientIds, avatar, name, 0);
|
||||||
@NonNull GroupId.V1 groupId,
|
}
|
||||||
@NonNull Set<Recipient> members,
|
|
||||||
@Nullable byte[] avatar,
|
|
||||||
@Nullable String name)
|
|
||||||
{
|
|
||||||
Set<RecipientId> addresses = getMemberIds(members);
|
|
||||||
|
|
||||||
return GroupManagerV1.updateGroup(context, groupId, addresses, avatar, name);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Set<RecipientId> getMemberIds(Collection<Recipient> recipients) {
|
private static Set<RecipientId> getMemberIds(Collection<Recipient> recipients) {
|
||||||
final Set<RecipientId> results = new HashSet<>();
|
Set<RecipientId> results = new HashSet<>(recipients.size());
|
||||||
|
|
||||||
for (Recipient recipient : recipients) {
|
for (Recipient recipient : recipients) {
|
||||||
results.add(recipient.getId());
|
results.add(recipient.getId());
|
||||||
}
|
}
|
||||||
@ -250,41 +232,59 @@ public final class GroupManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void addMembers(@NonNull Context context,
|
@WorkerThread
|
||||||
|
public static @NonNull GroupActionResult addMembers(@NonNull Context context,
|
||||||
@NonNull GroupId.Push groupId,
|
@NonNull GroupId.Push groupId,
|
||||||
@NonNull Collection<RecipientId> newMembers)
|
@NonNull Collection<RecipientId> newMembers)
|
||||||
throws GroupChangeFailedException, GroupInsufficientRightsException, IOException, GroupNotAMemberException, GroupChangeBusyException, MembershipNotSuitableForV2Exception
|
throws GroupChangeFailedException, GroupInsufficientRightsException, IOException, GroupNotAMemberException, GroupChangeBusyException, MembershipNotSuitableForV2Exception
|
||||||
{
|
{
|
||||||
if (groupId.isV2()) {
|
if (groupId.isV2()) {
|
||||||
try (GroupManagerV2.GroupEditor editor = new GroupManagerV2(context).edit(groupId.requireV2())) {
|
try (GroupManagerV2.GroupEditor editor = new GroupManagerV2(context).edit(groupId.requireV2())) {
|
||||||
editor.addMembers(newMembers);
|
return editor.addMembers(newMembers);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
GroupDatabase.GroupRecord groupRecord = DatabaseFactory.getGroupDatabase(context).requireGroup(groupId);
|
GroupDatabase.GroupRecord groupRecord = DatabaseFactory.getGroupDatabase(context).requireGroup(groupId);
|
||||||
List<RecipientId> members = groupRecord.getMembers();
|
List<RecipientId> members = groupRecord.getMembers();
|
||||||
byte[] avatar = groupRecord.hasAvatar() ? Util.readFully(AvatarHelper.getAvatar(context, groupRecord.getRecipientId())) : null;
|
byte[] avatar = groupRecord.hasAvatar() ? Util.readFully(AvatarHelper.getAvatar(context, groupRecord.getRecipientId())) : null;
|
||||||
Set<RecipientId> addresses = new HashSet<>(members);
|
Set<RecipientId> recipientIds = new HashSet<>(members);
|
||||||
|
int originalSize = recipientIds.size();
|
||||||
|
|
||||||
addresses.addAll(newMembers);
|
recipientIds.addAll(newMembers);
|
||||||
GroupManagerV1.updateGroup(context, groupId, addresses, avatar, groupRecord.getTitle());
|
return GroupManagerV1.updateGroup(context, groupId, recipientIds, avatar, groupRecord.getTitle(), recipientIds.size() - originalSize);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class GroupActionResult {
|
public static class GroupActionResult {
|
||||||
private final Recipient groupRecipient;
|
private final Recipient groupRecipient;
|
||||||
private final long threadId;
|
private final long threadId;
|
||||||
|
private final int addedMemberCount;
|
||||||
|
private final List<RecipientId> invitedMembers;
|
||||||
|
|
||||||
public GroupActionResult(Recipient groupRecipient, long threadId) {
|
public GroupActionResult(@NonNull Recipient groupRecipient,
|
||||||
|
long threadId,
|
||||||
|
int addedMemberCount,
|
||||||
|
@NonNull List<RecipientId> invitedMembers)
|
||||||
|
{
|
||||||
this.groupRecipient = groupRecipient;
|
this.groupRecipient = groupRecipient;
|
||||||
this.threadId = threadId;
|
this.threadId = threadId;
|
||||||
|
this.addedMemberCount = addedMemberCount;
|
||||||
|
this.invitedMembers = invitedMembers;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Recipient getGroupRecipient() {
|
public @NonNull Recipient getGroupRecipient() {
|
||||||
return groupRecipient;
|
return groupRecipient;
|
||||||
}
|
}
|
||||||
|
|
||||||
public long getThreadId() {
|
public long getThreadId() {
|
||||||
return threadId;
|
return threadId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getAddedMemberCount() {
|
||||||
|
return addedMemberCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public @NonNull List<RecipientId> getInvitedMembers() {
|
||||||
|
return invitedMembers;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -71,11 +71,11 @@ final class GroupManagerV1 {
|
|||||||
}
|
}
|
||||||
groupDatabase.onAvatarUpdated(groupIdV1, avatarBytes != null);
|
groupDatabase.onAvatarUpdated(groupIdV1, avatarBytes != null);
|
||||||
DatabaseFactory.getRecipientDatabase(context).setProfileSharing(groupRecipient.getId(), true);
|
DatabaseFactory.getRecipientDatabase(context).setProfileSharing(groupRecipient.getId(), true);
|
||||||
return sendGroupUpdate(context, groupIdV1, memberIds, name, avatarBytes);
|
return sendGroupUpdate(context, groupIdV1, memberIds, name, avatarBytes, memberIds.size() - 1);
|
||||||
} else {
|
} else {
|
||||||
groupDatabase.create(groupId.requireMms(), memberIds);
|
groupDatabase.create(groupId.requireMms(), memberIds);
|
||||||
long threadId = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(groupRecipient, ThreadDatabase.DistributionTypes.CONVERSATION);
|
long threadId = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(groupRecipient, ThreadDatabase.DistributionTypes.CONVERSATION);
|
||||||
return new GroupActionResult(groupRecipient, threadId);
|
return new GroupActionResult(groupRecipient, threadId, memberIds.size() - 1, Collections.emptyList());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -83,7 +83,8 @@ final class GroupManagerV1 {
|
|||||||
@NonNull GroupId groupId,
|
@NonNull GroupId groupId,
|
||||||
@NonNull Set<RecipientId> memberAddresses,
|
@NonNull Set<RecipientId> memberAddresses,
|
||||||
@Nullable byte[] avatarBytes,
|
@Nullable byte[] avatarBytes,
|
||||||
@Nullable String name)
|
@Nullable String name,
|
||||||
|
int newMemberCount)
|
||||||
{
|
{
|
||||||
final GroupDatabase groupDatabase = DatabaseFactory.getGroupDatabase(context);
|
final GroupDatabase groupDatabase = DatabaseFactory.getGroupDatabase(context);
|
||||||
final RecipientId groupRecipientId = DatabaseFactory.getRecipientDatabase(context).getOrInsertFromGroupId(groupId);
|
final RecipientId groupRecipientId = DatabaseFactory.getRecipientDatabase(context).getOrInsertFromGroupId(groupId);
|
||||||
@ -102,11 +103,11 @@ final class GroupManagerV1 {
|
|||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
Log.w(TAG, "Failed to save avatar!", e);
|
Log.w(TAG, "Failed to save avatar!", e);
|
||||||
}
|
}
|
||||||
return sendGroupUpdate(context, groupIdV1, memberAddresses, name, avatarBytes);
|
return sendGroupUpdate(context, groupIdV1, memberAddresses, name, avatarBytes, newMemberCount);
|
||||||
} else {
|
} else {
|
||||||
Recipient groupRecipient = Recipient.resolved(groupRecipientId);
|
Recipient groupRecipient = Recipient.resolved(groupRecipientId);
|
||||||
long threadId = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(groupRecipient);
|
long threadId = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(groupRecipient);
|
||||||
return new GroupActionResult(groupRecipient, threadId);
|
return new GroupActionResult(groupRecipient, threadId, newMemberCount, Collections.emptyList());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -114,7 +115,8 @@ final class GroupManagerV1 {
|
|||||||
@NonNull GroupId.V1 groupId,
|
@NonNull GroupId.V1 groupId,
|
||||||
@NonNull Set<RecipientId> members,
|
@NonNull Set<RecipientId> members,
|
||||||
@Nullable String groupName,
|
@Nullable String groupName,
|
||||||
@Nullable byte[] avatar)
|
@Nullable byte[] avatar,
|
||||||
|
int newMemberCount)
|
||||||
{
|
{
|
||||||
Attachment avatarAttachment = null;
|
Attachment avatarAttachment = null;
|
||||||
RecipientId groupRecipientId = DatabaseFactory.getRecipientDatabase(context).getOrInsertFromGroupId(groupId);
|
RecipientId groupRecipientId = DatabaseFactory.getRecipientDatabase(context).getOrInsertFromGroupId(groupId);
|
||||||
@ -144,7 +146,7 @@ final class GroupManagerV1 {
|
|||||||
OutgoingGroupUpdateMessage outgoingMessage = new OutgoingGroupUpdateMessage(groupRecipient, groupContext, avatarAttachment, System.currentTimeMillis(), 0, false, null, Collections.emptyList(), Collections.emptyList());
|
OutgoingGroupUpdateMessage outgoingMessage = new OutgoingGroupUpdateMessage(groupRecipient, groupContext, avatarAttachment, System.currentTimeMillis(), 0, false, null, Collections.emptyList(), Collections.emptyList());
|
||||||
long threadId = MessageSender.send(context, outgoingMessage, -1, false, null);
|
long threadId = MessageSender.send(context, outgoingMessage, -1, false, null);
|
||||||
|
|
||||||
return new GroupActionResult(groupRecipient, threadId);
|
return new GroupActionResult(groupRecipient, threadId, newMemberCount, Collections.emptyList());
|
||||||
}
|
}
|
||||||
|
|
||||||
@WorkerThread
|
@WorkerThread
|
||||||
|
@ -156,7 +156,12 @@ final class GroupManagerV2 {
|
|||||||
groupDatabase.onAvatarUpdated(groupId, avatar != null);
|
groupDatabase.onAvatarUpdated(groupId, avatar != null);
|
||||||
DatabaseFactory.getRecipientDatabase(context).setProfileSharing(groupRecipient.getId(), true);
|
DatabaseFactory.getRecipientDatabase(context).setProfileSharing(groupRecipient.getId(), true);
|
||||||
|
|
||||||
return sendGroupUpdate(masterKey, decryptedGroup, null, null);
|
RecipientAndThread recipientAndThread = sendGroupUpdate(masterKey, decryptedGroup, null, null);
|
||||||
|
|
||||||
|
return new GroupManager.GroupActionResult(recipientAndThread.groupRecipient,
|
||||||
|
recipientAndThread.threadId,
|
||||||
|
decryptedGroup.getMembersCount() - 1,
|
||||||
|
getPendingMemberRecipientIds(decryptedGroup.getPendingMembersList()));
|
||||||
} catch (VerificationFailedException | InvalidGroupStateException e) {
|
} catch (VerificationFailedException | InvalidGroupStateException e) {
|
||||||
throw new GroupChangeFailedException(e);
|
throw new GroupChangeFailedException(e);
|
||||||
}
|
}
|
||||||
@ -378,7 +383,7 @@ final class GroupManagerV2 {
|
|||||||
Recipient groupRecipient = Recipient.externalGroup(context, groupId);
|
Recipient groupRecipient = Recipient.externalGroup(context, groupId);
|
||||||
long threadId = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(groupRecipient);
|
long threadId = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(groupRecipient);
|
||||||
|
|
||||||
return new GroupManager.GroupActionResult(groupRecipient, threadId);
|
return new GroupManager.GroupActionResult(groupRecipient, threadId, 0, Collections.emptyList());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -429,7 +434,11 @@ final class GroupManagerV2 {
|
|||||||
GroupChange signedGroupChange = commitToServer(changeActions);
|
GroupChange signedGroupChange = commitToServer(changeActions);
|
||||||
groupDatabase.update(groupId, decryptedGroupState);
|
groupDatabase.update(groupId, decryptedGroupState);
|
||||||
|
|
||||||
return sendGroupUpdate(groupMasterKey, decryptedGroupState, decryptedChange, signedGroupChange);
|
RecipientAndThread recipientAndThread = sendGroupUpdate(groupMasterKey, decryptedGroupState, decryptedChange, signedGroupChange);
|
||||||
|
int newMembersCount = decryptedChange.getNewMembersCount();
|
||||||
|
List<RecipientId> newPendingMembers = getPendingMemberRecipientIds(decryptedChange.getNewPendingMembersList());
|
||||||
|
|
||||||
|
return new GroupManager.GroupActionResult(recipientAndThread.groupRecipient, recipientAndThread.threadId, newMembersCount, newPendingMembers);
|
||||||
}
|
}
|
||||||
|
|
||||||
private GroupChange commitToServer(GroupChange.Actions change)
|
private GroupChange commitToServer(GroupChange.Actions change)
|
||||||
@ -494,7 +503,7 @@ final class GroupManagerV2 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private @NonNull GroupManager.GroupActionResult sendGroupUpdate(@NonNull GroupMasterKey masterKey,
|
private @NonNull RecipientAndThread sendGroupUpdate(@NonNull GroupMasterKey masterKey,
|
||||||
@NonNull DecryptedGroup decryptedGroup,
|
@NonNull DecryptedGroup decryptedGroup,
|
||||||
@Nullable DecryptedGroupChange plainGroupChange,
|
@Nullable DecryptedGroupChange plainGroupChange,
|
||||||
@Nullable GroupChange signedGroupChange)
|
@Nullable GroupChange signedGroupChange)
|
||||||
@ -514,13 +523,19 @@ final class GroupManagerV2 {
|
|||||||
|
|
||||||
if (plainGroupChange != null && DecryptedGroupUtil.changeIsEmptyExceptForProfileKeyChanges(plainGroupChange)) {
|
if (plainGroupChange != null && DecryptedGroupUtil.changeIsEmptyExceptForProfileKeyChanges(plainGroupChange)) {
|
||||||
ApplicationDependencies.getJobManager().add(PushGroupSilentUpdateSendJob.create(context, groupId, decryptedGroup, outgoingMessage));
|
ApplicationDependencies.getJobManager().add(PushGroupSilentUpdateSendJob.create(context, groupId, decryptedGroup, outgoingMessage));
|
||||||
return new GroupManager.GroupActionResult(groupRecipient, -1);
|
return new RecipientAndThread(groupRecipient, -1);
|
||||||
} else {
|
} else {
|
||||||
long threadId = MessageSender.send(context, outgoingMessage, -1, false, null);
|
long threadId = MessageSender.send(context, outgoingMessage, -1, false, null);
|
||||||
return new GroupManager.GroupActionResult(groupRecipient, threadId);
|
return new RecipientAndThread(groupRecipient, threadId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static @NonNull List<RecipientId> getPendingMemberRecipientIds(@NonNull List<DecryptedPendingMember> newPendingMembersList) {
|
||||||
|
return Stream.of(DecryptedGroupUtil.pendingToUuidList(newPendingMembersList))
|
||||||
|
.map(uuid-> RecipientId.from(uuid,null))
|
||||||
|
.toList();
|
||||||
|
}
|
||||||
|
|
||||||
private static @NonNull AccessControl.AccessRequired rightsToAccessControl(@NonNull GroupAccessControl rights) {
|
private static @NonNull AccessControl.AccessRequired rightsToAccessControl(@NonNull GroupAccessControl rights) {
|
||||||
switch (rights){
|
switch (rights){
|
||||||
case ALL_MEMBERS:
|
case ALL_MEMBERS:
|
||||||
@ -531,4 +546,14 @@ final class GroupManagerV2 {
|
|||||||
throw new AssertionError();
|
throw new AssertionError();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static class RecipientAndThread {
|
||||||
|
private final Recipient groupRecipient;
|
||||||
|
private final long threadId;
|
||||||
|
|
||||||
|
RecipientAndThread(@NonNull Recipient groupRecipient, long threadId) {
|
||||||
|
this.groupRecipient = groupRecipient;
|
||||||
|
this.threadId = threadId;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,11 @@
|
|||||||
package org.thoughtcrime.securesms.groups.ui;
|
package org.thoughtcrime.securesms.groups.ui;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
|
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
public interface AddMembersResultCallback {
|
public interface AddMembersResultCallback {
|
||||||
void onMembersAdded(int numberOfMembersAdded);
|
void onMembersAdded(int numberOfMembersAdded, @NonNull List<RecipientId> invitedMembers);
|
||||||
}
|
}
|
||||||
|
@ -111,10 +111,17 @@ public abstract class GroupMemberEntry {
|
|||||||
private final UuidCiphertext inviteeCipherText;
|
private final UuidCiphertext inviteeCipherText;
|
||||||
private final boolean cancellable;
|
private final boolean cancellable;
|
||||||
|
|
||||||
public PendingMember(@NonNull Recipient invitee, @NonNull UuidCiphertext inviteeCipherText, boolean cancellable) {
|
public PendingMember(@NonNull Recipient invitee, @Nullable UuidCiphertext inviteeCipherText, boolean cancellable) {
|
||||||
this.invitee = invitee;
|
this.invitee = invitee;
|
||||||
this.inviteeCipherText = inviteeCipherText;
|
this.inviteeCipherText = inviteeCipherText;
|
||||||
this.cancellable = cancellable;
|
this.cancellable = cancellable;
|
||||||
|
if (cancellable && inviteeCipherText == null) {
|
||||||
|
throw new IllegalArgumentException("inviteeCipherText must be supplied to enable cancellation");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public PendingMember(@NonNull Recipient invitee) {
|
||||||
|
this(invitee, null, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Recipient getInvitee() {
|
public Recipient getInvitee() {
|
||||||
@ -122,6 +129,9 @@ public abstract class GroupMemberEntry {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public UuidCiphertext getInviteeCipherText() {
|
public UuidCiphertext getInviteeCipherText() {
|
||||||
|
if (!cancellable) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
return inviteeCipherText;
|
return inviteeCipherText;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package org.thoughtcrime.securesms.groups.ui.creategroup.details;
|
package org.thoughtcrime.securesms.groups.ui.creategroup.details;
|
||||||
|
|
||||||
|
import android.app.Dialog;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
@ -14,10 +15,14 @@ import org.thoughtcrime.securesms.PassphraseRequiredActivity;
|
|||||||
import org.thoughtcrime.securesms.R;
|
import org.thoughtcrime.securesms.R;
|
||||||
import org.thoughtcrime.securesms.conversation.ConversationActivity;
|
import org.thoughtcrime.securesms.conversation.ConversationActivity;
|
||||||
import org.thoughtcrime.securesms.database.ThreadDatabase;
|
import org.thoughtcrime.securesms.database.ThreadDatabase;
|
||||||
|
import org.thoughtcrime.securesms.groups.ui.managegroup.dialogs.GroupInviteSentDialog;
|
||||||
|
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||||
import org.thoughtcrime.securesms.util.DynamicNoActionBarTheme;
|
import org.thoughtcrime.securesms.util.DynamicNoActionBarTheme;
|
||||||
import org.thoughtcrime.securesms.util.DynamicTheme;
|
import org.thoughtcrime.securesms.util.DynamicTheme;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
public class AddGroupDetailsActivity extends PassphraseRequiredActivity implements AddGroupDetailsFragment.Callback {
|
public class AddGroupDetailsActivity extends PassphraseRequiredActivity implements AddGroupDetailsFragment.Callback {
|
||||||
|
|
||||||
private static final String EXTRA_RECIPIENTS = "recipient_ids";
|
private static final String EXTRA_RECIPIENTS = "recipient_ids";
|
||||||
@ -58,7 +63,19 @@ public class AddGroupDetailsActivity extends PassphraseRequiredActivity implemen
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onGroupCreated(@NonNull RecipientId recipientId, long threadId) {
|
public void onGroupCreated(@NonNull RecipientId recipientId,
|
||||||
|
long threadId,
|
||||||
|
@NonNull List<Recipient> invitedMembers)
|
||||||
|
{
|
||||||
|
Dialog dialog = GroupInviteSentDialog.showInvitesSent(this, invitedMembers);
|
||||||
|
if (dialog != null) {
|
||||||
|
dialog.setOnDismissListener((d) -> goToConversation(recipientId, threadId));
|
||||||
|
} else {
|
||||||
|
goToConversation(recipientId, threadId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void goToConversation(@NonNull RecipientId recipientId, long threadId) {
|
||||||
Intent intent = ConversationActivity.buildIntent(this,
|
Intent intent = ConversationActivity.buildIntent(this,
|
||||||
recipientId,
|
recipientId,
|
||||||
threadId,
|
threadId,
|
||||||
|
@ -20,7 +20,6 @@ import androidx.annotation.Nullable;
|
|||||||
import androidx.annotation.StringRes;
|
import androidx.annotation.StringRes;
|
||||||
import androidx.appcompat.app.AlertDialog;
|
import androidx.appcompat.app.AlertDialog;
|
||||||
import androidx.appcompat.widget.Toolbar;
|
import androidx.appcompat.widget.Toolbar;
|
||||||
import androidx.fragment.app.Fragment;
|
|
||||||
import androidx.lifecycle.ViewModelProviders;
|
import androidx.lifecycle.ViewModelProviders;
|
||||||
import androidx.vectordrawable.graphics.drawable.VectorDrawableCompat;
|
import androidx.vectordrawable.graphics.drawable.VectorDrawableCompat;
|
||||||
|
|
||||||
@ -45,6 +44,7 @@ import org.thoughtcrime.securesms.util.BitmapUtil;
|
|||||||
import org.thoughtcrime.securesms.util.ViewUtil;
|
import org.thoughtcrime.securesms.util.ViewUtil;
|
||||||
import org.thoughtcrime.securesms.util.text.AfterTextChanged;
|
import org.thoughtcrime.securesms.util.text.AfterTextChanged;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
public class AddGroupDetailsFragment extends LoggingFragment {
|
public class AddGroupDetailsFragment extends LoggingFragment {
|
||||||
@ -202,7 +202,7 @@ public class AddGroupDetailsFragment extends LoggingFragment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void handleGroupCreateResultSuccess(@NonNull GroupCreateResult.Success success) {
|
private void handleGroupCreateResultSuccess(@NonNull GroupCreateResult.Success success) {
|
||||||
callback.onGroupCreated(success.getGroupRecipient().getId(), success.getThreadId());
|
callback.onGroupCreated(success.getGroupRecipient().getId(), success.getThreadId(), success.getInvitedMembers());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleGroupCreateResultError(@NonNull GroupCreateResult.Error error) {
|
private void handleGroupCreateResultError(@NonNull GroupCreateResult.Error error) {
|
||||||
@ -252,7 +252,7 @@ public class AddGroupDetailsFragment extends LoggingFragment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public interface Callback {
|
public interface Callback {
|
||||||
void onGroupCreated(@NonNull RecipientId recipientId, long threadId);
|
void onGroupCreated(@NonNull RecipientId recipientId, long threadId, @NonNull List<Recipient> invitedMembers);
|
||||||
void onNavigationButtonPressed();
|
void onNavigationButtonPressed();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,15 +1,19 @@
|
|||||||
package org.thoughtcrime.securesms.groups.ui.creategroup.details;
|
package org.thoughtcrime.securesms.groups.ui.creategroup.details;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.WorkerThread;
|
||||||
import androidx.core.util.Consumer;
|
import androidx.core.util.Consumer;
|
||||||
|
|
||||||
import org.thoughtcrime.securesms.groups.GroupManager;
|
import org.thoughtcrime.securesms.groups.GroupManager;
|
||||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
abstract class GroupCreateResult {
|
abstract class GroupCreateResult {
|
||||||
|
|
||||||
|
@WorkerThread
|
||||||
static GroupCreateResult success(@NonNull GroupManager.GroupActionResult result) {
|
static GroupCreateResult success(@NonNull GroupManager.GroupActionResult result) {
|
||||||
return new GroupCreateResult.Success(result.getThreadId(), result.getGroupRecipient());
|
return new GroupCreateResult.Success(result.getThreadId(), result.getGroupRecipient(), result.getAddedMemberCount(), Recipient.resolvedList(result.getInvitedMembers()));
|
||||||
}
|
}
|
||||||
|
|
||||||
static GroupCreateResult error(@NonNull GroupCreateResult.Error.Type errorType) {
|
static GroupCreateResult error(@NonNull GroupCreateResult.Error.Type errorType) {
|
||||||
@ -22,10 +26,18 @@ abstract class GroupCreateResult {
|
|||||||
static final class Success extends GroupCreateResult {
|
static final class Success extends GroupCreateResult {
|
||||||
private final long threadId;
|
private final long threadId;
|
||||||
private final Recipient groupRecipient;
|
private final Recipient groupRecipient;
|
||||||
|
private final int addedMemberCount;
|
||||||
|
private final List<Recipient> invitedMembers;
|
||||||
|
|
||||||
private Success(long threadId, @NonNull Recipient groupRecipient) {
|
private Success(long threadId,
|
||||||
|
@NonNull Recipient groupRecipient,
|
||||||
|
int addedMemberCount,
|
||||||
|
@NonNull List<Recipient> invitedMembers)
|
||||||
|
{
|
||||||
this.threadId = threadId;
|
this.threadId = threadId;
|
||||||
this.groupRecipient = groupRecipient;
|
this.groupRecipient = groupRecipient;
|
||||||
|
this.addedMemberCount = addedMemberCount;
|
||||||
|
this.invitedMembers = invitedMembers;
|
||||||
}
|
}
|
||||||
|
|
||||||
long getThreadId() {
|
long getThreadId() {
|
||||||
@ -36,6 +48,14 @@ abstract class GroupCreateResult {
|
|||||||
return groupRecipient;
|
return groupRecipient;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int getAddedMemberCount() {
|
||||||
|
return addedMemberCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Recipient> getInvitedMembers() {
|
||||||
|
return invitedMembers;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
void consume(@NonNull Consumer<Success> successConsumer,
|
void consume(@NonNull Consumer<Success> successConsumer,
|
||||||
@NonNull Consumer<Error> errorConsumer)
|
@NonNull Consumer<Error> errorConsumer)
|
||||||
|
@ -37,6 +37,7 @@ import org.thoughtcrime.securesms.contacts.avatars.FallbackPhoto80dp;
|
|||||||
import org.thoughtcrime.securesms.groups.GroupId;
|
import org.thoughtcrime.securesms.groups.GroupId;
|
||||||
import org.thoughtcrime.securesms.groups.ui.GroupMemberListView;
|
import org.thoughtcrime.securesms.groups.ui.GroupMemberListView;
|
||||||
import org.thoughtcrime.securesms.groups.ui.LeaveGroupDialog;
|
import org.thoughtcrime.securesms.groups.ui.LeaveGroupDialog;
|
||||||
|
import org.thoughtcrime.securesms.groups.ui.managegroup.dialogs.GroupInviteSentDialog;
|
||||||
import org.thoughtcrime.securesms.groups.ui.managegroup.dialogs.GroupRightsDialog;
|
import org.thoughtcrime.securesms.groups.ui.managegroup.dialogs.GroupRightsDialog;
|
||||||
import org.thoughtcrime.securesms.groups.ui.pendingmemberinvites.PendingMemberInvitesActivity;
|
import org.thoughtcrime.securesms.groups.ui.pendingmemberinvites.PendingMemberInvitesActivity;
|
||||||
import org.thoughtcrime.securesms.logging.Log;
|
import org.thoughtcrime.securesms.logging.Log;
|
||||||
@ -317,6 +318,7 @@ public class ManageGroupFragment extends LoggingFragment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
viewModel.getSnackbarEvents().observe(getViewLifecycleOwner(), this::handleSnackbarEvent);
|
viewModel.getSnackbarEvents().observe(getViewLifecycleOwner(), this::handleSnackbarEvent);
|
||||||
|
viewModel.getInvitedDialogEvents().observe(getViewLifecycleOwner(), this::handleInvitedDialogEvent);
|
||||||
|
|
||||||
viewModel.getCanLeaveGroup().observe(getViewLifecycleOwner(), canLeave -> leaveGroup.setVisibility(canLeave ? View.VISIBLE : View.GONE));
|
viewModel.getCanLeaveGroup().observe(getViewLifecycleOwner(), canLeave -> leaveGroup.setVisibility(canLeave ? View.VISIBLE : View.GONE));
|
||||||
viewModel.getCanBlockGroup().observe(getViewLifecycleOwner(), canBlock -> {
|
viewModel.getCanBlockGroup().observe(getViewLifecycleOwner(), canBlock -> {
|
||||||
@ -364,6 +366,10 @@ public class ManageGroupFragment extends LoggingFragment {
|
|||||||
Snackbar.make(requireView(), buildSnackbarString(snackbarEvent), Snackbar.LENGTH_SHORT).setTextColor(Color.WHITE).show();
|
Snackbar.make(requireView(), buildSnackbarString(snackbarEvent), Snackbar.LENGTH_SHORT).setTextColor(Color.WHITE).show();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void handleInvitedDialogEvent(@NonNull ManageGroupViewModel.InvitedDialogEvent invitedDialogEvent) {
|
||||||
|
GroupInviteSentDialog.showInvitesSent(requireContext(), invitedDialogEvent.getNewInvitedMembers());
|
||||||
|
}
|
||||||
|
|
||||||
private @NonNull String buildSnackbarString(@NonNull ManageGroupViewModel.SnackbarEvent snackbarEvent) {
|
private @NonNull String buildSnackbarString(@NonNull ManageGroupViewModel.SnackbarEvent snackbarEvent) {
|
||||||
return getResources().getQuantityString(R.plurals.ManageGroupActivity_added,
|
return getResources().getQuantityString(R.plurals.ManageGroupActivity_added,
|
||||||
snackbarEvent.getNumberOfMembersAdded(),
|
snackbarEvent.getNumberOfMembersAdded(),
|
||||||
|
@ -146,8 +146,8 @@ final class ManageGroupRepository {
|
|||||||
void addMembers(@NonNull List<RecipientId> selected, @NonNull AddMembersResultCallback addMembersResultCallback, @NonNull GroupChangeErrorCallback error) {
|
void addMembers(@NonNull List<RecipientId> selected, @NonNull AddMembersResultCallback addMembersResultCallback, @NonNull GroupChangeErrorCallback error) {
|
||||||
SignalExecutors.UNBOUNDED.execute(() -> {
|
SignalExecutors.UNBOUNDED.execute(() -> {
|
||||||
try {
|
try {
|
||||||
GroupManager.addMembers(context, groupId.requirePush(), selected);
|
GroupManager.GroupActionResult groupActionResult = GroupManager.addMembers(context, groupId.requirePush(), selected);
|
||||||
addMembersResultCallback.onMembersAdded(selected.size());
|
addMembersResultCallback.onMembersAdded(groupActionResult.getAddedMemberCount(), groupActionResult.getInvitedMembers());
|
||||||
} catch (GroupInsufficientRightsException | GroupNotAMemberException e) {
|
} catch (GroupInsufficientRightsException | GroupNotAMemberException e) {
|
||||||
Log.w(TAG, e);
|
Log.w(TAG, e);
|
||||||
error.onError(GroupChangeFailureReason.NO_RIGHTS);
|
error.onError(GroupChangeFailureReason.NO_RIGHTS);
|
||||||
|
@ -25,8 +25,6 @@ import org.thoughtcrime.securesms.database.MediaDatabase;
|
|||||||
import org.thoughtcrime.securesms.database.loaders.MediaLoader;
|
import org.thoughtcrime.securesms.database.loaders.MediaLoader;
|
||||||
import org.thoughtcrime.securesms.database.loaders.ThreadMediaLoader;
|
import org.thoughtcrime.securesms.database.loaders.ThreadMediaLoader;
|
||||||
import org.thoughtcrime.securesms.groups.GroupAccessControl;
|
import org.thoughtcrime.securesms.groups.GroupAccessControl;
|
||||||
import org.thoughtcrime.securesms.groups.GroupChangeBusyException;
|
|
||||||
import org.thoughtcrime.securesms.groups.GroupChangeFailedException;
|
|
||||||
import org.thoughtcrime.securesms.groups.GroupId;
|
import org.thoughtcrime.securesms.groups.GroupId;
|
||||||
import org.thoughtcrime.securesms.groups.LiveGroup;
|
import org.thoughtcrime.securesms.groups.LiveGroup;
|
||||||
import org.thoughtcrime.securesms.groups.ui.GroupChangeFailureReason;
|
import org.thoughtcrime.securesms.groups.ui.GroupChangeFailureReason;
|
||||||
@ -43,7 +41,6 @@ import org.thoughtcrime.securesms.util.SingleLiveEvent;
|
|||||||
import org.thoughtcrime.securesms.util.Util;
|
import org.thoughtcrime.securesms.util.Util;
|
||||||
import org.thoughtcrime.securesms.util.livedata.LiveDataUtil;
|
import org.thoughtcrime.securesms.util.livedata.LiveDataUtil;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@ -54,6 +51,7 @@ public class ManageGroupViewModel extends ViewModel {
|
|||||||
private final Context context;
|
private final Context context;
|
||||||
private final ManageGroupRepository manageGroupRepository;
|
private final ManageGroupRepository manageGroupRepository;
|
||||||
private final SingleLiveEvent<SnackbarEvent> snackbarEvents = new SingleLiveEvent<>();
|
private final SingleLiveEvent<SnackbarEvent> snackbarEvents = new SingleLiveEvent<>();
|
||||||
|
private final SingleLiveEvent<InvitedDialogEvent> invitedDialogEvents = new SingleLiveEvent<>();
|
||||||
private final LiveData<String> title;
|
private final LiveData<String> title;
|
||||||
private final LiveData<Boolean> isAdmin;
|
private final LiveData<Boolean> isAdmin;
|
||||||
private final LiveData<Boolean> canEditGroupAttributes;
|
private final LiveData<Boolean> canEditGroupAttributes;
|
||||||
@ -91,7 +89,7 @@ public class ManageGroupViewModel extends ViewModel {
|
|||||||
(state, hasEnoughMembers) -> state != CollapseState.OPEN && hasEnoughMembers);
|
(state, hasEnoughMembers) -> state != CollapseState.OPEN && hasEnoughMembers);
|
||||||
this.members = LiveDataUtil.combineLatest(liveGroup.getFullMembers(),
|
this.members = LiveDataUtil.combineLatest(liveGroup.getFullMembers(),
|
||||||
memberListCollapseState,
|
memberListCollapseState,
|
||||||
this::filterMemberList);
|
ManageGroupViewModel::filterMemberList);
|
||||||
this.pendingMemberCount = liveGroup.getPendingMemberCount();
|
this.pendingMemberCount = liveGroup.getPendingMemberCount();
|
||||||
this.memberCountSummary = liveGroup.getMembershipCountDescription(context.getResources());
|
this.memberCountSummary = liveGroup.getMembershipCountDescription(context.getResources());
|
||||||
this.fullMemberCountSummary = liveGroup.getFullMembershipCountDescription(context.getResources());
|
this.fullMemberCountSummary = liveGroup.getFullMembershipCountDescription(context.getResources());
|
||||||
@ -180,6 +178,10 @@ public class ManageGroupViewModel extends ViewModel {
|
|||||||
return snackbarEvents;
|
return snackbarEvents;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SingleLiveEvent<InvitedDialogEvent> getInvitedDialogEvents() {
|
||||||
|
return invitedDialogEvents;
|
||||||
|
}
|
||||||
|
|
||||||
LiveData<Boolean> getCanCollapseMemberList() {
|
LiveData<Boolean> getCanCollapseMemberList() {
|
||||||
return canCollapseMemberList;
|
return canCollapseMemberList;
|
||||||
}
|
}
|
||||||
@ -220,7 +222,7 @@ public class ManageGroupViewModel extends ViewModel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void onAddMembers(List<RecipientId> selected) {
|
void onAddMembers(List<RecipientId> selected) {
|
||||||
manageGroupRepository.addMembers(selected, this::showSuccessSnackbar, this::showErrorToast);
|
manageGroupRepository.addMembers(selected, this::showAddSuccess, this::showErrorToast);
|
||||||
}
|
}
|
||||||
|
|
||||||
void setMuteUntil(long muteUntil) {
|
void setMuteUntil(long muteUntil) {
|
||||||
@ -235,7 +237,7 @@ public class ManageGroupViewModel extends ViewModel {
|
|||||||
memberListCollapseState.setValue(CollapseState.OPEN);
|
memberListCollapseState.setValue(CollapseState.OPEN);
|
||||||
}
|
}
|
||||||
|
|
||||||
private @NonNull List<GroupMemberEntry.FullMember> filterMemberList(@NonNull List<GroupMemberEntry.FullMember> members,
|
private static @NonNull List<GroupMemberEntry.FullMember> filterMemberList(@NonNull List<GroupMemberEntry.FullMember> members,
|
||||||
@NonNull CollapseState collapseState)
|
@NonNull CollapseState collapseState)
|
||||||
{
|
{
|
||||||
if (collapseState == CollapseState.COLLAPSED && members.size() > MAX_COLLAPSED_MEMBERS) {
|
if (collapseState == CollapseState.COLLAPSED && members.size() > MAX_COLLAPSED_MEMBERS) {
|
||||||
@ -246,9 +248,15 @@ public class ManageGroupViewModel extends ViewModel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@WorkerThread
|
@WorkerThread
|
||||||
private void showSuccessSnackbar(int numberOfMembersAdded) {
|
private void showAddSuccess(int numberOfMembersAdded, @NonNull List<RecipientId> newInvitedMembers) {
|
||||||
|
if (!newInvitedMembers.isEmpty()) {
|
||||||
|
invitedDialogEvents.postValue(new InvitedDialogEvent(Recipient.resolvedList(newInvitedMembers)));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (numberOfMembersAdded > 0) {
|
||||||
snackbarEvents.postValue(new SnackbarEvent(numberOfMembersAdded));
|
snackbarEvents.postValue(new SnackbarEvent(numberOfMembersAdded));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@WorkerThread
|
@WorkerThread
|
||||||
private void showErrorToast(@NonNull GroupChangeFailureReason e) {
|
private void showErrorToast(@NonNull GroupChangeFailureReason e) {
|
||||||
@ -328,6 +336,19 @@ public class ManageGroupViewModel extends ViewModel {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static final class InvitedDialogEvent {
|
||||||
|
|
||||||
|
private final List<Recipient> newInvitedMembers;
|
||||||
|
|
||||||
|
private InvitedDialogEvent(@NonNull List<Recipient> newInvitedMembers) {
|
||||||
|
this.newInvitedMembers = newInvitedMembers;
|
||||||
|
}
|
||||||
|
|
||||||
|
public @NonNull List<Recipient> getNewInvitedMembers() {
|
||||||
|
return newInvitedMembers;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private enum CollapseState {
|
private enum CollapseState {
|
||||||
OPEN,
|
OPEN,
|
||||||
COLLAPSED
|
COLLAPSED
|
||||||
|
@ -0,0 +1,57 @@
|
|||||||
|
package org.thoughtcrime.securesms.groups.ui.managegroup.dialogs;
|
||||||
|
|
||||||
|
import android.app.Dialog;
|
||||||
|
import android.content.Context;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
import androidx.appcompat.app.AlertDialog;
|
||||||
|
|
||||||
|
import org.thoughtcrime.securesms.R;
|
||||||
|
import org.thoughtcrime.securesms.groups.ui.GroupMemberEntry;
|
||||||
|
import org.thoughtcrime.securesms.groups.ui.GroupMemberListView;
|
||||||
|
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public final class GroupInviteSentDialog {
|
||||||
|
|
||||||
|
private GroupInviteSentDialog() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static @Nullable Dialog showInvitesSent(@NonNull Context context, @NonNull List<Recipient> recipients) {
|
||||||
|
int size = recipients.size();
|
||||||
|
if (size == 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
AlertDialog.Builder builder = new AlertDialog.Builder(context)
|
||||||
|
.setTitle(context.getResources().getQuantityString(R.plurals.GroupManagement_invitation_sent, size, size))
|
||||||
|
// TODO: GV2 Need a URL for learn more
|
||||||
|
// .setNegativeButton(R.string.GroupManagement_learn_more, (dialog, which) -> {
|
||||||
|
// })
|
||||||
|
.setPositiveButton(android.R.string.ok, null);
|
||||||
|
if (size == 1) {
|
||||||
|
builder.setMessage(context.getString(R.string.GroupManagement_invite_single_user, recipients.get(0).getDisplayName(context)));
|
||||||
|
} else {
|
||||||
|
builder.setMessage(R.string.GroupManagement_invite_multiple_users)
|
||||||
|
.setView(R.layout.dialog_multiple_group_invites_sent);
|
||||||
|
}
|
||||||
|
|
||||||
|
Dialog dialog = builder.show();
|
||||||
|
if (size > 1) {
|
||||||
|
GroupMemberListView invitees = dialog.findViewById(R.id.list_invitees);
|
||||||
|
|
||||||
|
List<GroupMemberEntry.PendingMember> pendingMembers = new ArrayList<>(recipients.size());
|
||||||
|
for (Recipient r : recipients) {
|
||||||
|
pendingMembers.add(new GroupMemberEntry.PendingMember(r));
|
||||||
|
}
|
||||||
|
|
||||||
|
//noinspection ConstantConditions
|
||||||
|
invitees.setMembers(pendingMembers);
|
||||||
|
}
|
||||||
|
|
||||||
|
return dialog;
|
||||||
|
}
|
||||||
|
}
|
@ -80,7 +80,7 @@ class EditPushGroupProfileRepository implements EditProfileRepository {
|
|||||||
{
|
{
|
||||||
SimpleTask.run(() -> {
|
SimpleTask.run(() -> {
|
||||||
try {
|
try {
|
||||||
GroupManager.updateGroup(context, groupId, avatar, avatarChanged, displayName, displayNameChanged);
|
GroupManager.updateGroupDetails(context, groupId, avatar, avatarChanged, displayName, displayNameChanged);
|
||||||
|
|
||||||
return UploadResult.SUCCESS;
|
return UploadResult.SUCCESS;
|
||||||
} catch (GroupChangeFailedException | GroupInsufficientRightsException | IOException | GroupNotAMemberException | GroupChangeBusyException e) {
|
} catch (GroupChangeFailedException | GroupInsufficientRightsException | IOException | GroupNotAMemberException | GroupChangeBusyException e) {
|
||||||
|
@ -47,6 +47,7 @@ import org.whispersystems.signalservice.api.push.SignalServiceAddress;
|
|||||||
import org.whispersystems.signalservice.api.util.UuidUtil;
|
import org.whispersystems.signalservice.api.util.UuidUtil;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -125,6 +126,17 @@ public class Recipient {
|
|||||||
return live(id).resolve();
|
return live(id).resolve();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@WorkerThread
|
||||||
|
public static @NonNull List<Recipient> resolvedList(@NonNull Collection<RecipientId> ids) {
|
||||||
|
List<Recipient> recipients = new ArrayList<>(ids.size());
|
||||||
|
|
||||||
|
for (RecipientId recipientId : ids) {
|
||||||
|
recipients.add(resolved(recipientId));
|
||||||
|
}
|
||||||
|
|
||||||
|
return recipients;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a fully-populated {@link Recipient} and associates it with the provided username.
|
* Returns a fully-populated {@link Recipient} and associates it with the provided username.
|
||||||
*/
|
*/
|
||||||
|
@ -0,0 +1,19 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
<org.thoughtcrime.securesms.groups.ui.GroupMemberListView
|
||||||
|
android:id="@+id/list_invitees"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:scrollbars="vertical"
|
||||||
|
android:scrollIndicators="top|bottom"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:maxHeight="100dp" />
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
@ -472,6 +472,15 @@
|
|||||||
<item>@string/GroupManagement_access_level_only_admins</item>
|
<item>@string/GroupManagement_access_level_only_admins</item>
|
||||||
</array>
|
</array>
|
||||||
|
|
||||||
|
<!-- GV2 invites sent -->
|
||||||
|
<plurals name="GroupManagement_invitation_sent">
|
||||||
|
<item quantity="one">Invitation sent</item>
|
||||||
|
<item quantity="other">%d invitations sent</item>
|
||||||
|
</plurals>
|
||||||
|
<string name="GroupManagement_invite_single_user">“%1$s” can’t be automatically added to this group by you.\n\nThey’ve been invited to join, and won’t see any group messages until they accept.</string>
|
||||||
|
<string name="GroupManagement_learn_more">Learn more</string>
|
||||||
|
<string name="GroupManagement_invite_multiple_users">These users can’t be automatically added to this group by you.\n\nThey’ve been invited to join the group, and won’t see any group messages until they accept.</string>
|
||||||
|
|
||||||
<!-- PendingMembersActivity -->
|
<!-- PendingMembersActivity -->
|
||||||
<string name="PendingMemberInvitesActivity_pending_group_invites">Pending group invites</string>
|
<string name="PendingMemberInvitesActivity_pending_group_invites">Pending group invites</string>
|
||||||
<string name="PendingMembersActivity_people_you_invited">People you invited</string>
|
<string name="PendingMembersActivity_people_you_invited">People you invited</string>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user