mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-04-26 03:40:56 +01:00
GV2 leave and eject operations.
This commit is contained in:
@@ -12,22 +12,18 @@ import com.annimon.stream.Stream;
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.contacts.sync.DirectoryHelper;
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||
import org.thoughtcrime.securesms.database.GroupDatabase;
|
||||
import org.thoughtcrime.securesms.database.RecipientDatabase.RegisteredState;
|
||||
import org.thoughtcrime.securesms.database.ThreadDatabase;
|
||||
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.LeaveGroupJob;
|
||||
import org.thoughtcrime.securesms.jobs.MultiDeviceBlockedUpdateJob;
|
||||
import org.thoughtcrime.securesms.jobs.MultiDeviceMessageRequestResponseJob;
|
||||
import org.thoughtcrime.securesms.jobs.RotateProfileKeyJob;
|
||||
import org.thoughtcrime.securesms.keyvalue.SignalStore;
|
||||
import org.thoughtcrime.securesms.logging.Log;
|
||||
import org.thoughtcrime.securesms.mms.OutgoingGroupUpdateMessage;
|
||||
import org.thoughtcrime.securesms.storage.StorageSyncHelper;
|
||||
import org.thoughtcrime.securesms.util.FeatureFlags;
|
||||
import org.thoughtcrime.securesms.util.GroupUtil;
|
||||
import org.whispersystems.libsignal.util.guava.Optional;
|
||||
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
|
||||
|
||||
@@ -116,23 +112,9 @@ public class RecipientUtil {
|
||||
throw new AssertionError("Not a group!");
|
||||
}
|
||||
|
||||
if (DatabaseFactory.getGroupDatabase(context).isActive(resolved.requireGroupId())) {
|
||||
long threadId = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(resolved);
|
||||
Optional<OutgoingGroupUpdateMessage> leaveMessage = GroupUtil.createGroupLeaveMessage(context, resolved);
|
||||
|
||||
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.");
|
||||
if (!GroupManager.silentLeaveGroup(context, resolved.requireGroupId().requirePush())) {
|
||||
Log.w(TAG, "Failed to leave group.");
|
||||
Toast.makeText(context, R.string.RecipientPreferenceActivity_error_leaving_group, Toast.LENGTH_LONG).show();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Button;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
@@ -40,6 +41,7 @@ public final class RecipientBottomSheetDialogFragment extends BottomSheetDialogF
|
||||
private Button makeGroupAdminButton;
|
||||
private Button removeAdminButton;
|
||||
private Button removeFromGroupButton;
|
||||
private ProgressBar adminActionBusy;
|
||||
|
||||
public static BottomSheetDialogFragment create(@NonNull RecipientId recipientId,
|
||||
@Nullable GroupId groupId)
|
||||
@@ -80,6 +82,7 @@ public final class RecipientBottomSheetDialogFragment extends BottomSheetDialogF
|
||||
makeGroupAdminButton = view.findViewById(R.id.make_group_admin_button);
|
||||
removeAdminButton = view.findViewById(R.id.remove_group_admin_button);
|
||||
removeFromGroupButton = view.findViewById(R.id.remove_from_group_button);
|
||||
adminActionBusy = view.findViewById(R.id.admin_action_busy);
|
||||
|
||||
return view;
|
||||
}
|
||||
@@ -150,8 +153,17 @@ public final class RecipientBottomSheetDialogFragment extends BottomSheetDialogF
|
||||
blockButton.setOnClickListener(view -> viewModel.onBlockClicked(requireActivity()));
|
||||
unblockButton.setOnClickListener(view -> viewModel.onUnblockClicked(requireActivity()));
|
||||
|
||||
makeGroupAdminButton.setOnClickListener(view -> viewModel.onMakeGroupAdminClicked());
|
||||
removeAdminButton.setOnClickListener(view -> viewModel.onRemoveGroupAdminClicked());
|
||||
removeFromGroupButton.setOnClickListener(view -> viewModel.onRemoveFromGroupClicked());
|
||||
makeGroupAdminButton.setOnClickListener(view -> viewModel.onMakeGroupAdminClicked(requireActivity()));
|
||||
removeAdminButton.setOnClickListener(view -> viewModel.onRemoveGroupAdminClicked(requireActivity()));
|
||||
|
||||
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.Nullable;
|
||||
import androidx.core.util.Consumer;
|
||||
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||
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.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.RecipientId;
|
||||
import org.thoughtcrime.securesms.util.concurrent.SignalExecutors;
|
||||
import org.thoughtcrime.securesms.util.concurrent.SimpleTask;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Objects;
|
||||
|
||||
final class RecipientDialogRepository {
|
||||
|
||||
private static final String TAG = Log.tag(RecipientDialogRepository.class);
|
||||
|
||||
@NonNull private final Context context;
|
||||
@NonNull private final RecipientId recipientId;
|
||||
@Nullable private final GroupId groupId;
|
||||
@@ -52,6 +66,48 @@ final class RecipientDialogRepository {
|
||||
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 {
|
||||
void remoteIdentity(@Nullable IdentityDatabase.IdentityRecord identityRecord);
|
||||
}
|
||||
|
||||
@@ -2,9 +2,12 @@ package org.thoughtcrime.securesms.recipients.ui.bottomsheet;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.WorkerThread;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.fragment.app.FragmentActivity;
|
||||
import androidx.lifecycle.LiveData;
|
||||
import androidx.lifecycle.MutableLiveData;
|
||||
@@ -12,17 +15,23 @@ import androidx.lifecycle.ViewModel;
|
||||
import androidx.lifecycle.ViewModelProvider;
|
||||
|
||||
import org.thoughtcrime.securesms.BlockUnblockDialog;
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.RecipientPreferenceActivity;
|
||||
import org.thoughtcrime.securesms.VerifyIdentityActivity;
|
||||
import org.thoughtcrime.securesms.database.IdentityDatabase;
|
||||
import org.thoughtcrime.securesms.groups.GroupId;
|
||||
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.RecipientId;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientUtil;
|
||||
import org.thoughtcrime.securesms.util.CommunicationActions;
|
||||
import org.thoughtcrime.securesms.util.Util;
|
||||
import org.thoughtcrime.securesms.util.livedata.LiveDataUtil;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
final class RecipientDialogViewModel extends ViewModel {
|
||||
|
||||
private final Context context;
|
||||
@@ -30,6 +39,7 @@ final class RecipientDialogViewModel extends ViewModel {
|
||||
private final LiveData<Recipient> recipient;
|
||||
private final MutableLiveData<IdentityDatabase.IdentityRecord> identity;
|
||||
private final LiveData<AdminActionStatus> adminActionStatus;
|
||||
private final MutableLiveData<Boolean> adminActionBusy;
|
||||
|
||||
private RecipientDialogViewModel(@NonNull Context context,
|
||||
@NonNull RecipientDialogRepository recipientDialogRepository)
|
||||
@@ -37,6 +47,7 @@ final class RecipientDialogViewModel extends ViewModel {
|
||||
this.context = context;
|
||||
this.recipientDialogRepository = recipientDialogRepository;
|
||||
this.identity = new MutableLiveData<>();
|
||||
this.adminActionBusy = new MutableLiveData<>(false);
|
||||
|
||||
boolean recipientIsSelf = recipientDialogRepository.getRecipientId().equals(Recipient.self().getId());
|
||||
|
||||
@@ -72,6 +83,10 @@ final class RecipientDialogViewModel extends ViewModel {
|
||||
return identity;
|
||||
}
|
||||
|
||||
LiveData<Boolean> getAdminActionBusy() {
|
||||
return adminActionBusy;
|
||||
}
|
||||
|
||||
void onMessageClicked(@NonNull Activity activity) {
|
||||
recipientDialogRepository.getRecipient(recipient -> CommunicationActions.startConversation(activity, recipient, null));
|
||||
}
|
||||
@@ -96,19 +111,64 @@ final class RecipientDialogViewModel extends ViewModel {
|
||||
activity.startActivity(RecipientPreferenceActivity.getLaunchIntent(activity, recipientDialogRepository.getRecipientId()));
|
||||
}
|
||||
|
||||
void onMakeGroupAdminClicked() {
|
||||
// TODO GV2
|
||||
throw new AssertionError("NYI");
|
||||
void onMakeGroupAdminClicked(@NonNull Activity activity) {
|
||||
new AlertDialog.Builder(activity)
|
||||
.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() {
|
||||
// TODO GV2
|
||||
throw new AssertionError("NYI");
|
||||
void onRemoveGroupAdminClicked(@NonNull Activity activity) {
|
||||
new AlertDialog.Builder(activity)
|
||||
.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() {
|
||||
// TODO GV2
|
||||
throw new AssertionError("NYI");
|
||||
void onRemoveFromGroupClicked(@NonNull Activity activity, @NonNull Runnable onSuccess) {
|
||||
recipientDialogRepository.getGroupName(title ->
|
||||
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 {
|
||||
|
||||
Reference in New Issue
Block a user