mirror of
https://github.com/oxen-io/session-android.git
synced 2025-06-09 06:18:34 +00:00
GV2 leave and eject operations.
This commit is contained in:
parent
b191341c57
commit
b800477365
@ -77,8 +77,44 @@ public final class GroupManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@WorkerThread
|
@WorkerThread
|
||||||
public static boolean leaveGroup(@NonNull Context context, @NonNull GroupId.Push groupId) {
|
public static void leaveGroup(@NonNull Context context, @NonNull GroupId.Push groupId)
|
||||||
return GroupManagerV1.leaveGroup(context, groupId.requireV1());
|
throws GroupChangeBusyException, GroupChangeFailedException, IOException
|
||||||
|
{
|
||||||
|
if (groupId.isV2()) {
|
||||||
|
try (GroupManagerV2.GroupEditor edit = new GroupManagerV2(context).edit(groupId.requireV2())) {
|
||||||
|
edit.leaveGroup();
|
||||||
|
Log.i(TAG, "Left group " + groupId);
|
||||||
|
} catch (GroupInsufficientRightsException e) {
|
||||||
|
Log.w(TAG, "Unexpected prevention from leaving " + groupId + " due to rights", e);
|
||||||
|
throw new GroupChangeFailedException(e);
|
||||||
|
} catch (GroupNotAMemberException e) {
|
||||||
|
Log.w(TAG, "Already left group " + groupId, e);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!GroupManagerV1.leaveGroup(context, groupId.requireV1())) {
|
||||||
|
Log.w(TAG, "GV1 group leave failed" + groupId);
|
||||||
|
throw new GroupChangeFailedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@WorkerThread
|
||||||
|
public static boolean silentLeaveGroup(@NonNull Context context, @NonNull GroupId.Push groupId) {
|
||||||
|
if (groupId.isV2()) {
|
||||||
|
throw new AssertionError("NYI"); // TODO [Alan] GV2 support silent leave for block and leave operations on GV2
|
||||||
|
} else {
|
||||||
|
return GroupManagerV1.silentLeaveGroup(context, groupId.requireV1());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@WorkerThread
|
||||||
|
public static void ejectFromGroup(@NonNull Context context, @NonNull GroupId.V2 groupId, @NonNull Recipient recipient)
|
||||||
|
throws GroupChangeBusyException, GroupChangeFailedException, GroupInsufficientRightsException, GroupNotAMemberException, IOException
|
||||||
|
{
|
||||||
|
try (GroupManagerV2.GroupEditor edit = new GroupManagerV2(context).edit(groupId.requireV2())) {
|
||||||
|
edit.ejectMember(recipient.getId());
|
||||||
|
Log.i(TAG, "Member removed from group " + groupId);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@WorkerThread
|
@WorkerThread
|
||||||
|
@ -171,10 +171,35 @@ final class GroupManagerV1 {
|
|||||||
groupDatabase.remove(groupId, Recipient.self().getId());
|
groupDatabase.remove(groupId, Recipient.self().getId());
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
|
Log.i(TAG, "Group was already inactive. Skipping.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@WorkerThread
|
||||||
|
static boolean silentLeaveGroup(@NonNull Context context, @NonNull GroupId.V1 groupId) {
|
||||||
|
if (DatabaseFactory.getGroupDatabase(context).isActive(groupId)) {
|
||||||
|
Recipient groupRecipient = Recipient.externalGroup(context, groupId);
|
||||||
|
long threadId = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(groupRecipient);
|
||||||
|
Optional<OutgoingGroupUpdateMessage> leaveMessage = GroupUtil.createGroupLeaveMessage(context, groupRecipient);
|
||||||
|
|
||||||
|
if (threadId != -1 && leaveMessage.isPresent()) {
|
||||||
|
ApplicationDependencies.getJobManager().add(LeaveGroupJob.create(groupRecipient));
|
||||||
|
|
||||||
|
GroupDatabase groupDatabase = DatabaseFactory.getGroupDatabase(context);
|
||||||
|
groupDatabase.setActive(groupId, false);
|
||||||
|
groupDatabase.remove(groupId, Recipient.self().getId());
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
Log.w(TAG, "Failed to leave group.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Log.i(TAG, "Group was already inactive. Skipping.");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@WorkerThread
|
@WorkerThread
|
||||||
static void updateGroupTimer(@NonNull Context context, @NonNull GroupId.V1 groupId, int expirationTime) {
|
static void updateGroupTimer(@NonNull Context context, @NonNull GroupId.V1 groupId, int expirationTime) {
|
||||||
RecipientDatabase recipientDatabase = DatabaseFactory.getRecipientDatabase(context);
|
RecipientDatabase recipientDatabase = DatabaseFactory.getRecipientDatabase(context);
|
||||||
|
@ -245,6 +245,27 @@ final class GroupManagerV2 {
|
|||||||
return commitChangeWithConflictResolution(groupOperations.createChangeMemberRole(recipient.getUuid().get(), admin ? Member.Role.ADMINISTRATOR : Member.Role.DEFAULT));
|
return commitChangeWithConflictResolution(groupOperations.createChangeMemberRole(recipient.getUuid().get(), admin ? Member.Role.ADMINISTRATOR : Member.Role.DEFAULT));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@WorkerThread
|
||||||
|
@NonNull GroupManager.GroupActionResult leaveGroup()
|
||||||
|
throws GroupChangeFailedException, GroupInsufficientRightsException, IOException, GroupNotAMemberException
|
||||||
|
{
|
||||||
|
return ejectMember(Recipient.self().getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
@WorkerThread
|
||||||
|
@NonNull GroupManager.GroupActionResult ejectMember(@NonNull RecipientId recipientId)
|
||||||
|
throws GroupChangeFailedException, GroupInsufficientRightsException, IOException, GroupNotAMemberException
|
||||||
|
{
|
||||||
|
Recipient recipient = Recipient.resolved(recipientId);
|
||||||
|
GroupManager.GroupActionResult result = commitChangeWithConflictResolution(groupOperations.createRemoveMembersChange(Collections.singleton(recipient.getUuid().get())));
|
||||||
|
|
||||||
|
if (recipient.isLocalNumber()) {
|
||||||
|
groupDatabase.setActive(groupId, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
@WorkerThread
|
@WorkerThread
|
||||||
@Nullable GroupManager.GroupActionResult updateSelfProfileKeyInGroup()
|
@Nullable GroupManager.GroupActionResult updateSelfProfileKeyInGroup()
|
||||||
throws GroupChangeFailedException, GroupInsufficientRightsException, IOException, GroupNotAMemberException
|
throws GroupChangeFailedException, GroupInsufficientRightsException, IOException, GroupNotAMemberException
|
||||||
|
@ -0,0 +1,7 @@
|
|||||||
|
package org.thoughtcrime.securesms.groups.ui;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
|
public interface GroupChangeErrorCallback {
|
||||||
|
void onError(@NonNull GroupChangeFailureReason failureReason);
|
||||||
|
}
|
@ -0,0 +1,8 @@
|
|||||||
|
package org.thoughtcrime.securesms.groups.ui;
|
||||||
|
|
||||||
|
public enum GroupChangeFailureReason {
|
||||||
|
NO_RIGHTS,
|
||||||
|
NOT_CAPABLE,
|
||||||
|
NOT_A_MEMBER,
|
||||||
|
OTHER
|
||||||
|
}
|
@ -0,0 +1,20 @@
|
|||||||
|
package org.thoughtcrime.securesms.groups.ui;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.StringRes;
|
||||||
|
|
||||||
|
import org.thoughtcrime.securesms.R;
|
||||||
|
|
||||||
|
public final class GroupErrors {
|
||||||
|
private GroupErrors() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static @StringRes int getUserDisplayMessage(@NonNull GroupChangeFailureReason failureReason) {
|
||||||
|
switch (failureReason) {
|
||||||
|
case NO_RIGHTS : return R.string.ManageGroupActivity_you_dont_have_the_rights_to_do_this;
|
||||||
|
case NOT_CAPABLE : return R.string.ManageGroupActivity_not_capable;
|
||||||
|
case NOT_A_MEMBER: return R.string.ManageGroupActivity_youre_not_a_member_of_the_group;
|
||||||
|
default : return R.string.ManageGroupActivity_failed_to_update_the_group;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -9,12 +9,19 @@ import androidx.appcompat.app.AlertDialog;
|
|||||||
import androidx.lifecycle.Lifecycle;
|
import androidx.lifecycle.Lifecycle;
|
||||||
|
|
||||||
import org.thoughtcrime.securesms.R;
|
import org.thoughtcrime.securesms.R;
|
||||||
|
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.GroupManager;
|
import org.thoughtcrime.securesms.groups.GroupManager;
|
||||||
|
import org.thoughtcrime.securesms.logging.Log;
|
||||||
import org.thoughtcrime.securesms.util.concurrent.SimpleTask;
|
import org.thoughtcrime.securesms.util.concurrent.SimpleTask;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
public final class LeaveGroupDialog {
|
public final class LeaveGroupDialog {
|
||||||
|
|
||||||
|
private static final String TAG = Log.tag(LeaveGroupDialog.class);
|
||||||
|
|
||||||
private LeaveGroupDialog() {
|
private LeaveGroupDialog() {
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -31,8 +38,16 @@ public final class LeaveGroupDialog {
|
|||||||
.setPositiveButton(R.string.yes, (dialog, which) ->
|
.setPositiveButton(R.string.yes, (dialog, which) ->
|
||||||
SimpleTask.run(
|
SimpleTask.run(
|
||||||
lifecycle,
|
lifecycle,
|
||||||
() -> GroupManager.leaveGroup(context, groupId),
|
() -> {
|
||||||
(success) -> {
|
try {
|
||||||
|
GroupManager.leaveGroup(context, groupId);
|
||||||
|
return true;
|
||||||
|
} catch (GroupChangeFailedException | GroupChangeBusyException | IOException e) {
|
||||||
|
Log.w(TAG, e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
(success) -> {
|
||||||
if (success) {
|
if (success) {
|
||||||
if (onSuccess != null) onSuccess.run();
|
if (onSuccess != null) onSuccess.run();
|
||||||
} else {
|
} else {
|
||||||
|
@ -3,11 +3,9 @@ package org.thoughtcrime.securesms.groups.ui.managegroup;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.StringRes;
|
|
||||||
import androidx.annotation.WorkerThread;
|
import androidx.annotation.WorkerThread;
|
||||||
import androidx.core.util.Consumer;
|
import androidx.core.util.Consumer;
|
||||||
|
|
||||||
import org.thoughtcrime.securesms.R;
|
|
||||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||||
import org.thoughtcrime.securesms.database.ThreadDatabase;
|
import org.thoughtcrime.securesms.database.ThreadDatabase;
|
||||||
import org.thoughtcrime.securesms.groups.GroupAccessControl;
|
import org.thoughtcrime.securesms.groups.GroupAccessControl;
|
||||||
@ -18,6 +16,8 @@ import org.thoughtcrime.securesms.groups.GroupInsufficientRightsException;
|
|||||||
import org.thoughtcrime.securesms.groups.GroupManager;
|
import org.thoughtcrime.securesms.groups.GroupManager;
|
||||||
import org.thoughtcrime.securesms.groups.GroupNotAMemberException;
|
import org.thoughtcrime.securesms.groups.GroupNotAMemberException;
|
||||||
import org.thoughtcrime.securesms.groups.MembershipNotSuitableForV2Exception;
|
import org.thoughtcrime.securesms.groups.MembershipNotSuitableForV2Exception;
|
||||||
|
import org.thoughtcrime.securesms.groups.ui.GroupChangeErrorCallback;
|
||||||
|
import org.thoughtcrime.securesms.groups.ui.GroupChangeFailureReason;
|
||||||
import org.thoughtcrime.securesms.logging.Log;
|
import org.thoughtcrime.securesms.logging.Log;
|
||||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||||
@ -26,7 +26,6 @@ import org.thoughtcrime.securesms.util.concurrent.SimpleTask;
|
|||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.ExecutorService;
|
|
||||||
|
|
||||||
final class ManageGroupRepository {
|
final class ManageGroupRepository {
|
||||||
|
|
||||||
@ -57,47 +56,47 @@ final class ManageGroupRepository {
|
|||||||
return new GroupStateResult(threadId, groupRecipient);
|
return new GroupStateResult(threadId, groupRecipient);
|
||||||
}
|
}
|
||||||
|
|
||||||
void setExpiration(int newExpirationTime, @NonNull Error error) {
|
void setExpiration(int newExpirationTime, @NonNull GroupChangeErrorCallback error) {
|
||||||
SignalExecutors.UNBOUNDED.execute(() -> {
|
SignalExecutors.UNBOUNDED.execute(() -> {
|
||||||
try {
|
try {
|
||||||
GroupManager.updateGroupTimer(context, groupId.requirePush(), newExpirationTime);
|
GroupManager.updateGroupTimer(context, groupId.requirePush(), newExpirationTime);
|
||||||
} catch (GroupInsufficientRightsException e) {
|
} catch (GroupInsufficientRightsException e) {
|
||||||
Log.w(TAG, e);
|
Log.w(TAG, e);
|
||||||
error.onError(FailureReason.NO_RIGHTS);
|
error.onError(GroupChangeFailureReason.NO_RIGHTS);
|
||||||
} catch (GroupNotAMemberException e) {
|
} catch (GroupNotAMemberException e) {
|
||||||
Log.w(TAG, e);
|
Log.w(TAG, e);
|
||||||
error.onError(FailureReason.NOT_A_MEMBER);
|
error.onError(GroupChangeFailureReason.NOT_A_MEMBER);
|
||||||
} catch (GroupChangeFailedException | GroupChangeBusyException | IOException e) {
|
} catch (GroupChangeFailedException | GroupChangeBusyException | IOException e) {
|
||||||
Log.w(TAG, e);
|
Log.w(TAG, e);
|
||||||
error.onError(FailureReason.OTHER);
|
error.onError(GroupChangeFailureReason.OTHER);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void applyMembershipRightsChange(@NonNull GroupAccessControl newRights, @NonNull Error error) {
|
void applyMembershipRightsChange(@NonNull GroupAccessControl newRights, @NonNull GroupChangeErrorCallback error) {
|
||||||
SignalExecutors.UNBOUNDED.execute(() -> {
|
SignalExecutors.UNBOUNDED.execute(() -> {
|
||||||
try {
|
try {
|
||||||
GroupManager.applyMembershipAdditionRightsChange(context, groupId.requireV2(), newRights);
|
GroupManager.applyMembershipAdditionRightsChange(context, groupId.requireV2(), newRights);
|
||||||
} catch (GroupInsufficientRightsException | GroupNotAMemberException e) {
|
} catch (GroupInsufficientRightsException | GroupNotAMemberException e) {
|
||||||
Log.w(TAG, e);
|
Log.w(TAG, e);
|
||||||
error.onError(FailureReason.NO_RIGHTS);
|
error.onError(GroupChangeFailureReason.NO_RIGHTS);
|
||||||
} catch (GroupChangeFailedException | GroupChangeBusyException | IOException e) {
|
} catch (GroupChangeFailedException | GroupChangeBusyException | IOException e) {
|
||||||
Log.w(TAG, e);
|
Log.w(TAG, e);
|
||||||
error.onError(FailureReason.OTHER);
|
error.onError(GroupChangeFailureReason.OTHER);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void applyAttributesRightsChange(@NonNull GroupAccessControl newRights, @NonNull Error error) {
|
void applyAttributesRightsChange(@NonNull GroupAccessControl newRights, @NonNull GroupChangeErrorCallback error) {
|
||||||
SignalExecutors.UNBOUNDED.execute(() -> {
|
SignalExecutors.UNBOUNDED.execute(() -> {
|
||||||
try {
|
try {
|
||||||
GroupManager.applyAttributesRightsChange(context, groupId.requireV2(), newRights);
|
GroupManager.applyAttributesRightsChange(context, groupId.requireV2(), newRights);
|
||||||
} catch (GroupInsufficientRightsException | GroupNotAMemberException e) {
|
} catch (GroupInsufficientRightsException | GroupNotAMemberException e) {
|
||||||
Log.w(TAG, e);
|
Log.w(TAG, e);
|
||||||
error.onError(FailureReason.NO_RIGHTS);
|
error.onError(GroupChangeFailureReason.NO_RIGHTS);
|
||||||
} catch (GroupChangeFailedException | GroupChangeBusyException | IOException e) {
|
} catch (GroupChangeFailedException | GroupChangeBusyException | IOException e) {
|
||||||
Log.w(TAG, e);
|
Log.w(TAG, e);
|
||||||
error.onError(FailureReason.OTHER);
|
error.onError(GroupChangeFailureReason.OTHER);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -115,19 +114,19 @@ final class ManageGroupRepository {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void addMembers(@NonNull List<RecipientId> selected, @NonNull Error error) {
|
void addMembers(@NonNull List<RecipientId> selected, @NonNull GroupChangeErrorCallback error) {
|
||||||
SignalExecutors.UNBOUNDED.execute(() -> {
|
SignalExecutors.UNBOUNDED.execute(() -> {
|
||||||
try {
|
try {
|
||||||
GroupManager.addMembers(context, groupId, selected);
|
GroupManager.addMembers(context, groupId, selected);
|
||||||
} catch (GroupInsufficientRightsException | GroupNotAMemberException e) {
|
} catch (GroupInsufficientRightsException | GroupNotAMemberException e) {
|
||||||
Log.w(TAG, e);
|
Log.w(TAG, e);
|
||||||
error.onError(FailureReason.NO_RIGHTS);
|
error.onError(GroupChangeFailureReason.NO_RIGHTS);
|
||||||
} catch (GroupChangeFailedException | GroupChangeBusyException | IOException e) {
|
} catch (GroupChangeFailedException | GroupChangeBusyException | IOException e) {
|
||||||
Log.w(TAG, e);
|
Log.w(TAG, e);
|
||||||
error.onError(FailureReason.OTHER);
|
error.onError(GroupChangeFailureReason.OTHER);
|
||||||
} catch (MembershipNotSuitableForV2Exception e) {
|
} catch (MembershipNotSuitableForV2Exception e) {
|
||||||
Log.w(TAG, e);
|
Log.w(TAG, e);
|
||||||
error.onError(FailureReason.NOT_CAPABLE);
|
error.onError(GroupChangeFailureReason.NOT_CAPABLE);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -153,24 +152,4 @@ final class ManageGroupRepository {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum FailureReason {
|
|
||||||
NO_RIGHTS(R.string.ManageGroupActivity_you_dont_have_the_rights_to_do_this),
|
|
||||||
NOT_CAPABLE(R.string.ManageGroupActivity_not_capable),
|
|
||||||
NOT_A_MEMBER(R.string.ManageGroupActivity_youre_not_a_member_of_the_group),
|
|
||||||
OTHER(R.string.ManageGroupActivity_failed_to_update_the_group);
|
|
||||||
|
|
||||||
private final @StringRes int toastMessage;
|
|
||||||
|
|
||||||
FailureReason(@StringRes int toastMessage) {
|
|
||||||
this.toastMessage = toastMessage;
|
|
||||||
}
|
|
||||||
|
|
||||||
public @StringRes int getToastMessage() {
|
|
||||||
return toastMessage;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public interface Error {
|
|
||||||
void onError(@NonNull FailureReason failureReason);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -21,6 +21,8 @@ import org.thoughtcrime.securesms.database.loaders.ThreadMediaLoader;
|
|||||||
import org.thoughtcrime.securesms.groups.GroupAccessControl;
|
import org.thoughtcrime.securesms.groups.GroupAccessControl;
|
||||||
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.GroupErrors;
|
||||||
import org.thoughtcrime.securesms.groups.ui.GroupMemberEntry;
|
import org.thoughtcrime.securesms.groups.ui.GroupMemberEntry;
|
||||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||||
@ -205,8 +207,8 @@ public class ManageGroupViewModel extends ViewModel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@WorkerThread
|
@WorkerThread
|
||||||
private void showErrorToast(@NonNull ManageGroupRepository.FailureReason e) {
|
private void showErrorToast(@NonNull GroupChangeFailureReason e) {
|
||||||
Util.runOnMain(() -> Toast.makeText(context, e.getToastMessage(), Toast.LENGTH_LONG).show());
|
Util.runOnMain(() -> Toast.makeText(context, GroupErrors.getUserDisplayMessage(e), Toast.LENGTH_LONG).show());
|
||||||
}
|
}
|
||||||
|
|
||||||
static final class GroupViewState {
|
static final class GroupViewState {
|
||||||
|
@ -125,7 +125,7 @@ public class LeaveGroupJob extends BaseJob {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static @NonNull List<Recipient> deliver(@NonNull Context context,
|
private static @NonNull List<Recipient> deliver(@NonNull Context context,
|
||||||
@NonNull GroupId groupId,
|
@NonNull GroupId.Push groupId,
|
||||||
@NonNull String name,
|
@NonNull String name,
|
||||||
@NonNull List<RecipientId> members,
|
@NonNull List<RecipientId> members,
|
||||||
@NonNull List<RecipientId> destinations)
|
@NonNull List<RecipientId> destinations)
|
||||||
|
@ -12,22 +12,18 @@ import com.annimon.stream.Stream;
|
|||||||
import org.thoughtcrime.securesms.R;
|
import org.thoughtcrime.securesms.R;
|
||||||
import org.thoughtcrime.securesms.contacts.sync.DirectoryHelper;
|
import org.thoughtcrime.securesms.contacts.sync.DirectoryHelper;
|
||||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||||
import org.thoughtcrime.securesms.database.GroupDatabase;
|
|
||||||
import org.thoughtcrime.securesms.database.RecipientDatabase.RegisteredState;
|
import org.thoughtcrime.securesms.database.RecipientDatabase.RegisteredState;
|
||||||
import org.thoughtcrime.securesms.database.ThreadDatabase;
|
import org.thoughtcrime.securesms.database.ThreadDatabase;
|
||||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
||||||
import org.thoughtcrime.securesms.groups.GroupId;
|
import org.thoughtcrime.securesms.groups.GroupManager;
|
||||||
import org.thoughtcrime.securesms.jobs.DirectoryRefreshJob;
|
import org.thoughtcrime.securesms.jobs.DirectoryRefreshJob;
|
||||||
import org.thoughtcrime.securesms.jobs.LeaveGroupJob;
|
|
||||||
import org.thoughtcrime.securesms.jobs.MultiDeviceBlockedUpdateJob;
|
import org.thoughtcrime.securesms.jobs.MultiDeviceBlockedUpdateJob;
|
||||||
import org.thoughtcrime.securesms.jobs.MultiDeviceMessageRequestResponseJob;
|
import org.thoughtcrime.securesms.jobs.MultiDeviceMessageRequestResponseJob;
|
||||||
import org.thoughtcrime.securesms.jobs.RotateProfileKeyJob;
|
import org.thoughtcrime.securesms.jobs.RotateProfileKeyJob;
|
||||||
import org.thoughtcrime.securesms.keyvalue.SignalStore;
|
import org.thoughtcrime.securesms.keyvalue.SignalStore;
|
||||||
import org.thoughtcrime.securesms.logging.Log;
|
import org.thoughtcrime.securesms.logging.Log;
|
||||||
import org.thoughtcrime.securesms.mms.OutgoingGroupUpdateMessage;
|
|
||||||
import org.thoughtcrime.securesms.storage.StorageSyncHelper;
|
import org.thoughtcrime.securesms.storage.StorageSyncHelper;
|
||||||
import org.thoughtcrime.securesms.util.FeatureFlags;
|
import org.thoughtcrime.securesms.util.FeatureFlags;
|
||||||
import org.thoughtcrime.securesms.util.GroupUtil;
|
|
||||||
import org.whispersystems.libsignal.util.guava.Optional;
|
import org.whispersystems.libsignal.util.guava.Optional;
|
||||||
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
|
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
|
||||||
|
|
||||||
@ -116,23 +112,9 @@ public class RecipientUtil {
|
|||||||
throw new AssertionError("Not a group!");
|
throw new AssertionError("Not a group!");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (DatabaseFactory.getGroupDatabase(context).isActive(resolved.requireGroupId())) {
|
if (!GroupManager.silentLeaveGroup(context, resolved.requireGroupId().requirePush())) {
|
||||||
long threadId = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(resolved);
|
Log.w(TAG, "Failed to leave group.");
|
||||||
Optional<OutgoingGroupUpdateMessage> leaveMessage = GroupUtil.createGroupLeaveMessage(context, resolved);
|
Toast.makeText(context, R.string.RecipientPreferenceActivity_error_leaving_group, Toast.LENGTH_LONG).show();
|
||||||
|
|
||||||
if (threadId != -1 && leaveMessage.isPresent()) {
|
|
||||||
ApplicationDependencies.getJobManager().add(LeaveGroupJob.create(recipient));
|
|
||||||
|
|
||||||
GroupDatabase groupDatabase = DatabaseFactory.getGroupDatabase(context);
|
|
||||||
GroupId groupId = resolved.requireGroupId();
|
|
||||||
groupDatabase.setActive(groupId, false);
|
|
||||||
groupDatabase.remove(groupId, Recipient.self().getId());
|
|
||||||
} else {
|
|
||||||
Log.w(TAG, "Failed to leave group.");
|
|
||||||
Toast.makeText(context, R.string.RecipientPreferenceActivity_error_leaving_group, Toast.LENGTH_LONG).show();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Log.i(TAG, "Group was already inactive. Skipping.");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,6 +6,7 @@ import android.view.LayoutInflater;
|
|||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.widget.Button;
|
import android.widget.Button;
|
||||||
|
import android.widget.ProgressBar;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
@ -40,6 +41,7 @@ public final class RecipientBottomSheetDialogFragment extends BottomSheetDialogF
|
|||||||
private Button makeGroupAdminButton;
|
private Button makeGroupAdminButton;
|
||||||
private Button removeAdminButton;
|
private Button removeAdminButton;
|
||||||
private Button removeFromGroupButton;
|
private Button removeFromGroupButton;
|
||||||
|
private ProgressBar adminActionBusy;
|
||||||
|
|
||||||
public static BottomSheetDialogFragment create(@NonNull RecipientId recipientId,
|
public static BottomSheetDialogFragment create(@NonNull RecipientId recipientId,
|
||||||
@Nullable GroupId groupId)
|
@Nullable GroupId groupId)
|
||||||
@ -80,6 +82,7 @@ public final class RecipientBottomSheetDialogFragment extends BottomSheetDialogF
|
|||||||
makeGroupAdminButton = view.findViewById(R.id.make_group_admin_button);
|
makeGroupAdminButton = view.findViewById(R.id.make_group_admin_button);
|
||||||
removeAdminButton = view.findViewById(R.id.remove_group_admin_button);
|
removeAdminButton = view.findViewById(R.id.remove_group_admin_button);
|
||||||
removeFromGroupButton = view.findViewById(R.id.remove_from_group_button);
|
removeFromGroupButton = view.findViewById(R.id.remove_from_group_button);
|
||||||
|
adminActionBusy = view.findViewById(R.id.admin_action_busy);
|
||||||
|
|
||||||
return view;
|
return view;
|
||||||
}
|
}
|
||||||
@ -150,8 +153,17 @@ public final class RecipientBottomSheetDialogFragment extends BottomSheetDialogF
|
|||||||
blockButton.setOnClickListener(view -> viewModel.onBlockClicked(requireActivity()));
|
blockButton.setOnClickListener(view -> viewModel.onBlockClicked(requireActivity()));
|
||||||
unblockButton.setOnClickListener(view -> viewModel.onUnblockClicked(requireActivity()));
|
unblockButton.setOnClickListener(view -> viewModel.onUnblockClicked(requireActivity()));
|
||||||
|
|
||||||
makeGroupAdminButton.setOnClickListener(view -> viewModel.onMakeGroupAdminClicked());
|
makeGroupAdminButton.setOnClickListener(view -> viewModel.onMakeGroupAdminClicked(requireActivity()));
|
||||||
removeAdminButton.setOnClickListener(view -> viewModel.onRemoveGroupAdminClicked());
|
removeAdminButton.setOnClickListener(view -> viewModel.onRemoveGroupAdminClicked(requireActivity()));
|
||||||
removeFromGroupButton.setOnClickListener(view -> viewModel.onRemoveFromGroupClicked());
|
|
||||||
|
removeFromGroupButton.setOnClickListener(view -> viewModel.onRemoveFromGroupClicked(requireActivity(), this::dismiss));
|
||||||
|
|
||||||
|
viewModel.getAdminActionBusy().observe(getViewLifecycleOwner(), busy -> {
|
||||||
|
adminActionBusy.setVisibility(busy ? View.VISIBLE : View.GONE);
|
||||||
|
|
||||||
|
makeGroupAdminButton.setEnabled(!busy);
|
||||||
|
removeAdminButton.setEnabled(!busy);
|
||||||
|
removeFromGroupButton.setEnabled(!busy);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,17 +4,31 @@ import android.content.Context;
|
|||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
import androidx.core.util.Consumer;
|
||||||
|
|
||||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||||
import org.thoughtcrime.securesms.database.IdentityDatabase;
|
import org.thoughtcrime.securesms.database.IdentityDatabase;
|
||||||
|
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.GroupInsufficientRightsException;
|
||||||
|
import org.thoughtcrime.securesms.groups.GroupManager;
|
||||||
|
import org.thoughtcrime.securesms.groups.GroupNotAMemberException;
|
||||||
|
import org.thoughtcrime.securesms.groups.ui.GroupChangeErrorCallback;
|
||||||
|
import org.thoughtcrime.securesms.groups.ui.GroupChangeFailureReason;
|
||||||
|
import org.thoughtcrime.securesms.logging.Log;
|
||||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||||
import org.thoughtcrime.securesms.util.concurrent.SignalExecutors;
|
import org.thoughtcrime.securesms.util.concurrent.SignalExecutors;
|
||||||
import org.thoughtcrime.securesms.util.concurrent.SimpleTask;
|
import org.thoughtcrime.securesms.util.concurrent.SimpleTask;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
final class RecipientDialogRepository {
|
final class RecipientDialogRepository {
|
||||||
|
|
||||||
|
private static final String TAG = Log.tag(RecipientDialogRepository.class);
|
||||||
|
|
||||||
@NonNull private final Context context;
|
@NonNull private final Context context;
|
||||||
@NonNull private final RecipientId recipientId;
|
@NonNull private final RecipientId recipientId;
|
||||||
@Nullable private final GroupId groupId;
|
@Nullable private final GroupId groupId;
|
||||||
@ -52,6 +66,48 @@ final class RecipientDialogRepository {
|
|||||||
recipientCallback::onRecipient);
|
recipientCallback::onRecipient);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void getGroupName(@NonNull Consumer<String> stringConsumer) {
|
||||||
|
SimpleTask.run(SignalExecutors.BOUNDED,
|
||||||
|
() -> DatabaseFactory.getGroupDatabase(context).requireGroup(Objects.requireNonNull(groupId)).getTitle(),
|
||||||
|
stringConsumer::accept);
|
||||||
|
}
|
||||||
|
|
||||||
|
void removeMember(@NonNull Consumer<Boolean> onComplete, @NonNull GroupChangeErrorCallback error) {
|
||||||
|
SimpleTask.run(SignalExecutors.UNBOUNDED,
|
||||||
|
() -> {
|
||||||
|
try {
|
||||||
|
GroupManager.ejectFromGroup(context, Objects.requireNonNull(groupId).requireV2(), Recipient.resolved(recipientId));
|
||||||
|
return true;
|
||||||
|
} catch (GroupInsufficientRightsException | GroupNotAMemberException e) {
|
||||||
|
Log.w(TAG, e);
|
||||||
|
error.onError(GroupChangeFailureReason.NO_RIGHTS);
|
||||||
|
} catch (GroupChangeFailedException | GroupChangeBusyException | IOException e) {
|
||||||
|
Log.w(TAG, e);
|
||||||
|
error.onError(GroupChangeFailureReason.OTHER);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
onComplete::accept);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setMemberAdmin(boolean admin, @NonNull Consumer<Boolean> onComplete, @NonNull GroupChangeErrorCallback error) {
|
||||||
|
SimpleTask.run(SignalExecutors.UNBOUNDED,
|
||||||
|
() -> {
|
||||||
|
try {
|
||||||
|
GroupManager.setMemberAdmin(context, Objects.requireNonNull(groupId).requireV2(), recipientId, admin);
|
||||||
|
return true;
|
||||||
|
} catch (GroupInsufficientRightsException | GroupNotAMemberException e) {
|
||||||
|
Log.w(TAG, e);
|
||||||
|
error.onError(GroupChangeFailureReason.NO_RIGHTS);
|
||||||
|
} catch (GroupChangeFailedException | GroupChangeBusyException | IOException e) {
|
||||||
|
Log.w(TAG, e);
|
||||||
|
error.onError(GroupChangeFailureReason.OTHER);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
onComplete::accept);
|
||||||
|
}
|
||||||
|
|
||||||
interface IdentityCallback {
|
interface IdentityCallback {
|
||||||
void remoteIdentity(@Nullable IdentityDatabase.IdentityRecord identityRecord);
|
void remoteIdentity(@Nullable IdentityDatabase.IdentityRecord identityRecord);
|
||||||
}
|
}
|
||||||
|
@ -2,9 +2,12 @@ package org.thoughtcrime.securesms.recipients.ui.bottomsheet;
|
|||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
import androidx.annotation.WorkerThread;
|
||||||
|
import androidx.appcompat.app.AlertDialog;
|
||||||
import androidx.fragment.app.FragmentActivity;
|
import androidx.fragment.app.FragmentActivity;
|
||||||
import androidx.lifecycle.LiveData;
|
import androidx.lifecycle.LiveData;
|
||||||
import androidx.lifecycle.MutableLiveData;
|
import androidx.lifecycle.MutableLiveData;
|
||||||
@ -12,17 +15,23 @@ import androidx.lifecycle.ViewModel;
|
|||||||
import androidx.lifecycle.ViewModelProvider;
|
import androidx.lifecycle.ViewModelProvider;
|
||||||
|
|
||||||
import org.thoughtcrime.securesms.BlockUnblockDialog;
|
import org.thoughtcrime.securesms.BlockUnblockDialog;
|
||||||
|
import org.thoughtcrime.securesms.R;
|
||||||
import org.thoughtcrime.securesms.RecipientPreferenceActivity;
|
import org.thoughtcrime.securesms.RecipientPreferenceActivity;
|
||||||
import org.thoughtcrime.securesms.VerifyIdentityActivity;
|
import org.thoughtcrime.securesms.VerifyIdentityActivity;
|
||||||
import org.thoughtcrime.securesms.database.IdentityDatabase;
|
import org.thoughtcrime.securesms.database.IdentityDatabase;
|
||||||
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.GroupErrors;
|
||||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||||
import org.thoughtcrime.securesms.recipients.RecipientUtil;
|
import org.thoughtcrime.securesms.recipients.RecipientUtil;
|
||||||
import org.thoughtcrime.securesms.util.CommunicationActions;
|
import org.thoughtcrime.securesms.util.CommunicationActions;
|
||||||
|
import org.thoughtcrime.securesms.util.Util;
|
||||||
import org.thoughtcrime.securesms.util.livedata.LiveDataUtil;
|
import org.thoughtcrime.securesms.util.livedata.LiveDataUtil;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
final class RecipientDialogViewModel extends ViewModel {
|
final class RecipientDialogViewModel extends ViewModel {
|
||||||
|
|
||||||
private final Context context;
|
private final Context context;
|
||||||
@ -30,6 +39,7 @@ final class RecipientDialogViewModel extends ViewModel {
|
|||||||
private final LiveData<Recipient> recipient;
|
private final LiveData<Recipient> recipient;
|
||||||
private final MutableLiveData<IdentityDatabase.IdentityRecord> identity;
|
private final MutableLiveData<IdentityDatabase.IdentityRecord> identity;
|
||||||
private final LiveData<AdminActionStatus> adminActionStatus;
|
private final LiveData<AdminActionStatus> adminActionStatus;
|
||||||
|
private final MutableLiveData<Boolean> adminActionBusy;
|
||||||
|
|
||||||
private RecipientDialogViewModel(@NonNull Context context,
|
private RecipientDialogViewModel(@NonNull Context context,
|
||||||
@NonNull RecipientDialogRepository recipientDialogRepository)
|
@NonNull RecipientDialogRepository recipientDialogRepository)
|
||||||
@ -37,6 +47,7 @@ final class RecipientDialogViewModel extends ViewModel {
|
|||||||
this.context = context;
|
this.context = context;
|
||||||
this.recipientDialogRepository = recipientDialogRepository;
|
this.recipientDialogRepository = recipientDialogRepository;
|
||||||
this.identity = new MutableLiveData<>();
|
this.identity = new MutableLiveData<>();
|
||||||
|
this.adminActionBusy = new MutableLiveData<>(false);
|
||||||
|
|
||||||
boolean recipientIsSelf = recipientDialogRepository.getRecipientId().equals(Recipient.self().getId());
|
boolean recipientIsSelf = recipientDialogRepository.getRecipientId().equals(Recipient.self().getId());
|
||||||
|
|
||||||
@ -72,6 +83,10 @@ final class RecipientDialogViewModel extends ViewModel {
|
|||||||
return identity;
|
return identity;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LiveData<Boolean> getAdminActionBusy() {
|
||||||
|
return adminActionBusy;
|
||||||
|
}
|
||||||
|
|
||||||
void onMessageClicked(@NonNull Activity activity) {
|
void onMessageClicked(@NonNull Activity activity) {
|
||||||
recipientDialogRepository.getRecipient(recipient -> CommunicationActions.startConversation(activity, recipient, null));
|
recipientDialogRepository.getRecipient(recipient -> CommunicationActions.startConversation(activity, recipient, null));
|
||||||
}
|
}
|
||||||
@ -96,19 +111,64 @@ final class RecipientDialogViewModel extends ViewModel {
|
|||||||
activity.startActivity(RecipientPreferenceActivity.getLaunchIntent(activity, recipientDialogRepository.getRecipientId()));
|
activity.startActivity(RecipientPreferenceActivity.getLaunchIntent(activity, recipientDialogRepository.getRecipientId()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void onMakeGroupAdminClicked() {
|
void onMakeGroupAdminClicked(@NonNull Activity activity) {
|
||||||
// TODO GV2
|
new AlertDialog.Builder(activity)
|
||||||
throw new AssertionError("NYI");
|
.setMessage(context.getString(R.string.RecipientBottomSheet_s_will_be_able_to_edit_group, Objects.requireNonNull(recipient.getValue()).toShortString(context)))
|
||||||
|
.setPositiveButton(R.string.RecipientBottomSheet_make_group_admin,
|
||||||
|
(dialog, which) -> {
|
||||||
|
adminActionBusy.setValue(true);
|
||||||
|
recipientDialogRepository.setMemberAdmin(true, result -> {
|
||||||
|
adminActionBusy.setValue(false);
|
||||||
|
if (!result) {
|
||||||
|
Toast.makeText(activity, R.string.ManageGroupActivity_failed_to_update_the_group, Toast.LENGTH_SHORT).show();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
this::showErrorToast);
|
||||||
|
})
|
||||||
|
.setNegativeButton(android.R.string.cancel, (dialog, which) -> {})
|
||||||
|
.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
void onRemoveGroupAdminClicked() {
|
void onRemoveGroupAdminClicked(@NonNull Activity activity) {
|
||||||
// TODO GV2
|
new AlertDialog.Builder(activity)
|
||||||
throw new AssertionError("NYI");
|
.setMessage(context.getString(R.string.RecipientBottomSheet_remove_s_as_group_admin, Objects.requireNonNull(recipient.getValue()).toShortString(context)))
|
||||||
|
.setPositiveButton(R.string.RecipientBottomSheet_remove_as_admin,
|
||||||
|
(dialog, which) -> {
|
||||||
|
adminActionBusy.setValue(true);
|
||||||
|
recipientDialogRepository.setMemberAdmin(false, result -> {
|
||||||
|
adminActionBusy.setValue(false);
|
||||||
|
if (!result) {
|
||||||
|
Toast.makeText(activity, R.string.ManageGroupActivity_failed_to_update_the_group, Toast.LENGTH_SHORT).show();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
this::showErrorToast);
|
||||||
|
})
|
||||||
|
.setNegativeButton(android.R.string.cancel, (dialog, which) -> {})
|
||||||
|
.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
void onRemoveFromGroupClicked() {
|
void onRemoveFromGroupClicked(@NonNull Activity activity, @NonNull Runnable onSuccess) {
|
||||||
// TODO GV2
|
recipientDialogRepository.getGroupName(title ->
|
||||||
throw new AssertionError("NYI");
|
new AlertDialog.Builder(activity)
|
||||||
|
.setMessage(context.getString(R.string.RecipientBottomSheet_remove_s_from_s, Objects.requireNonNull(recipient.getValue()).toShortString(context), title))
|
||||||
|
.setPositiveButton(R.string.RecipientBottomSheet_remove,
|
||||||
|
(dialog, which) -> {
|
||||||
|
adminActionBusy.setValue(true);
|
||||||
|
recipientDialogRepository.removeMember(result -> {
|
||||||
|
adminActionBusy.setValue(false);
|
||||||
|
if (result) {
|
||||||
|
onSuccess.run();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
this::showErrorToast);
|
||||||
|
})
|
||||||
|
.setNegativeButton(android.R.string.cancel, (dialog, which) -> {})
|
||||||
|
.show());
|
||||||
|
}
|
||||||
|
|
||||||
|
@WorkerThread
|
||||||
|
private void showErrorToast(@NonNull GroupChangeFailureReason e) {
|
||||||
|
Util.runOnMain(() -> Toast.makeText(context, GroupErrors.getUserDisplayMessage(e), Toast.LENGTH_LONG).show());
|
||||||
}
|
}
|
||||||
|
|
||||||
static class AdminActionStatus {
|
static class AdminActionStatus {
|
||||||
|
@ -2228,6 +2228,12 @@
|
|||||||
<string name="RecipientBottomSheet_remove_as_admin">Remove as admin</string>
|
<string name="RecipientBottomSheet_remove_as_admin">Remove as admin</string>
|
||||||
<string name="RecipientBottomSheet_remove_from_group">Remove from group</string>
|
<string name="RecipientBottomSheet_remove_from_group">Remove from group</string>
|
||||||
|
|
||||||
|
<string name="RecipientBottomSheet_remove_s_as_group_admin">Remove %1$s as group admin?</string>
|
||||||
|
<string name="RecipientBottomSheet_s_will_be_able_to_edit_group">%1$s will be able to edit this group and its members</string>
|
||||||
|
|
||||||
|
<string name="RecipientBottomSheet_remove_s_from_s">Remove %1$s from "%2$s"?</string>
|
||||||
|
<string name="RecipientBottomSheet_remove">Remove</string>
|
||||||
|
|
||||||
<string name="GroupRecipientListItem_admin">Admin</string>
|
<string name="GroupRecipientListItem_admin">Admin</string>
|
||||||
|
|
||||||
<!-- EOF -->
|
<!-- EOF -->
|
||||||
|
@ -192,6 +192,17 @@ public final class GroupsV2Operations {
|
|||||||
return actions;
|
return actions;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public GroupChange.Actions.Builder createRemoveMembersChange(final Set<UUID> membersToRemove) {
|
||||||
|
GroupChange.Actions.Builder actions = GroupChange.Actions.newBuilder();
|
||||||
|
|
||||||
|
for (UUID remove: membersToRemove) {
|
||||||
|
actions.addDeleteMembers(GroupChange.Actions.DeleteMemberAction.newBuilder()
|
||||||
|
.setDeletedUserId(encryptUuid(remove)));
|
||||||
|
}
|
||||||
|
|
||||||
|
return actions;
|
||||||
|
}
|
||||||
|
|
||||||
public GroupChange.Actions.Builder createModifyGroupTimerChange(int timerDurationSeconds) {
|
public GroupChange.Actions.Builder createModifyGroupTimerChange(int timerDurationSeconds) {
|
||||||
return GroupChange.Actions
|
return GroupChange.Actions
|
||||||
.newBuilder()
|
.newBuilder()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user