Added progress feedback to leave and block group actions and additional group v2 error handling.

master
Alan Evans 2020-07-20 15:20:56 -03:00 committed by GitHub
parent 9a566e5559
commit a33771b15d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
25 changed files with 216 additions and 188 deletions

View File

@ -148,12 +148,10 @@ import org.thoughtcrime.securesms.database.model.StickerRecord;
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
import org.thoughtcrime.securesms.events.ReminderUpdateEvent;
import org.thoughtcrime.securesms.giph.ui.GiphyActivity;
import org.thoughtcrime.securesms.groups.GroupChangeBusyException;
import org.thoughtcrime.securesms.groups.GroupChangeFailedException;
import org.thoughtcrime.securesms.groups.GroupInsufficientRightsException;
import org.thoughtcrime.securesms.groups.GroupChangeException;
import org.thoughtcrime.securesms.groups.GroupManager;
import org.thoughtcrime.securesms.groups.GroupNotAMemberException;
import org.thoughtcrime.securesms.groups.ui.GroupChangeFailureReason;
import org.thoughtcrime.securesms.groups.ui.GroupChangeResult;
import org.thoughtcrime.securesms.groups.ui.GroupErrors;
import org.thoughtcrime.securesms.groups.ui.LeaveGroupDialog;
import org.thoughtcrime.securesms.groups.ui.managegroup.ManageGroupActivity;
@ -1003,26 +1001,20 @@ public class ConversationActivity extends PassphraseRequiredActivity
if (activeGroup) {
try {
GroupManager.updateGroupTimer(ConversationActivity.this, getRecipient().requireGroupId().requirePush(), expirationTime);
} catch (GroupInsufficientRightsException e) {
} catch (GroupChangeException | IOException e) {
Log.w(TAG, e);
return ConversationActivity.this.getString(R.string.ManageGroupActivity_you_dont_have_the_rights_to_do_this);
} catch (GroupNotAMemberException e) {
Log.w(TAG, e);
return ConversationActivity.this.getString(R.string.ManageGroupActivity_youre_not_a_member_of_the_group);
} catch (GroupChangeFailedException | GroupChangeBusyException | IOException e) {
Log.w(TAG, e);
return ConversationActivity.this.getString(R.string.ManageGroupActivity_failed_to_update_the_group);
return GroupChangeResult.failure(GroupChangeFailureReason.fromException(e));
}
} else {
DatabaseFactory.getRecipientDatabase(ConversationActivity.this).setExpireMessages(recipient.getId(), expirationTime);
OutgoingExpirationUpdateMessage outgoingMessage = new OutgoingExpirationUpdateMessage(getRecipient(), System.currentTimeMillis(), expirationTime * 1000L);
MessageSender.send(ConversationActivity.this, outgoingMessage, threadId, false, null);
}
return null;
return GroupChangeResult.SUCCESS;
},
(errorString) -> {
if (errorString != null) {
Toast.makeText(ConversationActivity.this, errorString, Toast.LENGTH_SHORT).show();
(changeResult) -> {
if (changeResult.isSuccess()) {
Toast.makeText(ConversationActivity.this, GroupErrors.getUserDisplayMessage(changeResult.getFailureReason()), Toast.LENGTH_SHORT).show();
} else {
invalidateOptionsMenu();
if (fragment != null) fragment.setLastSeen(0);

View File

@ -2,7 +2,7 @@ package org.thoughtcrime.securesms.groups;
import androidx.annotation.NonNull;
public final class GroupChangeBusyException extends Exception {
public final class GroupChangeBusyException extends GroupChangeException {
public GroupChangeBusyException(@NonNull Throwable throwable) {
super(throwable);

View File

@ -0,0 +1,17 @@
package org.thoughtcrime.securesms.groups;
import androidx.annotation.NonNull;
public abstract class GroupChangeException extends Exception {
GroupChangeException() {
}
GroupChangeException(@NonNull Throwable throwable) {
super(throwable);
}
GroupChangeException(@NonNull String message) {
super(message);
}
}

View File

@ -2,7 +2,7 @@ package org.thoughtcrime.securesms.groups;
import androidx.annotation.NonNull;
public final class GroupChangeFailedException extends Exception {
public final class GroupChangeFailedException extends GroupChangeException {
GroupChangeFailedException() {
}

View File

@ -1,6 +1,6 @@
package org.thoughtcrime.securesms.groups;
public final class GroupInsufficientRightsException extends Exception {
public final class GroupInsufficientRightsException extends GroupChangeException {
GroupInsufficientRightsException(Throwable throwable) {
super(throwable);

View File

@ -1,6 +1,6 @@
package org.thoughtcrime.securesms.groups;
public final class GroupNotAMemberException extends Exception {
public final class GroupNotAMemberException extends GroupChangeException {
public GroupNotAMemberException(Throwable throwable) {
super(throwable);

View File

@ -1,8 +1,28 @@
package org.thoughtcrime.securesms.groups.ui;
import androidx.annotation.NonNull;
import org.thoughtcrime.securesms.groups.GroupChangeBusyException;
import org.thoughtcrime.securesms.groups.GroupInsufficientRightsException;
import org.thoughtcrime.securesms.groups.GroupNotAMemberException;
import org.thoughtcrime.securesms.groups.MembershipNotSuitableForV2Exception;
import java.io.IOException;
public enum GroupChangeFailureReason {
NO_RIGHTS,
NOT_CAPABLE,
NOT_A_MEMBER,
OTHER
BUSY,
NETWORK,
OTHER;
public static @NonNull GroupChangeFailureReason fromException(@NonNull Exception e) {
if (e instanceof MembershipNotSuitableForV2Exception) return GroupChangeFailureReason.NOT_CAPABLE;
if (e instanceof IOException) return GroupChangeFailureReason.NETWORK;
if (e instanceof GroupNotAMemberException) return GroupChangeFailureReason.NOT_A_MEMBER;
if (e instanceof GroupChangeBusyException) return GroupChangeFailureReason.BUSY;
if (e instanceof GroupInsufficientRightsException) return GroupChangeFailureReason.NO_RIGHTS;
return GroupChangeFailureReason.OTHER;
}
}

View File

@ -0,0 +1,31 @@
package org.thoughtcrime.securesms.groups.ui;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
public final class GroupChangeResult {
public final static GroupChangeResult SUCCESS = new GroupChangeResult(null);
private final @Nullable GroupChangeFailureReason failureReason;
GroupChangeResult(@Nullable GroupChangeFailureReason failureReason) {
this.failureReason = failureReason;
}
public static GroupChangeResult failure(@NonNull GroupChangeFailureReason failureReason) {
return new GroupChangeResult(failureReason);
}
public boolean isSuccess() {
return failureReason == null;
}
public @NonNull GroupChangeFailureReason getFailureReason() {
if (isSuccess()) {
throw new UnsupportedOperationException();
}
return failureReason;
}
}

View File

@ -14,6 +14,8 @@ public final class GroupErrors {
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;
case BUSY : return R.string.ManageGroupActivity_failed_to_update_the_group_please_retry_later;
case NETWORK : return R.string.ManageGroupActivity_failed_to_update_the_group_due_to_a_network_error_please_retry_later;
default : return R.string.ManageGroupActivity_failed_to_update_the_group;
}
}

View File

@ -12,14 +12,14 @@ import com.annimon.stream.Stream;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.database.GroupDatabase;
import org.thoughtcrime.securesms.groups.GroupChangeBusyException;
import org.thoughtcrime.securesms.groups.GroupChangeFailedException;
import org.thoughtcrime.securesms.groups.GroupChangeException;
import org.thoughtcrime.securesms.groups.GroupId;
import org.thoughtcrime.securesms.groups.GroupManager;
import org.thoughtcrime.securesms.groups.ui.chooseadmin.ChooseNewAdminActivity;
import org.thoughtcrime.securesms.logging.Log;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.util.concurrent.SimpleTask;
import org.thoughtcrime.securesms.util.views.SimpleProgressDialog;
import java.io.IOException;
import java.util.List;
@ -90,26 +90,32 @@ public final class LeaveGroupDialog {
.setIconAttribute(R.attr.dialog_info_icon)
.setCancelable(true)
.setMessage(R.string.ConversationActivity_are_you_sure_you_want_to_leave_this_group)
.setPositiveButton(R.string.yes, (dialog, which) -> SimpleTask.run(activity.getLifecycle(), this::leaveGroup, this::handleLeaveGroupResult))
.setPositiveButton(R.string.yes, (dialog, which) -> {
SimpleProgressDialog.DismissibleDialog progressDialog = SimpleProgressDialog.showDelayed(activity);
SimpleTask.run(activity.getLifecycle(), this::leaveGroup, result -> {
progressDialog.dismiss();
handleLeaveGroupResult(result);
});
})
.setNegativeButton(R.string.no, null)
.show();
}
private boolean leaveGroup() {
private @NonNull GroupChangeResult leaveGroup() {
try {
GroupManager.leaveGroup(activity, groupId);
return true;
} catch (GroupChangeFailedException | GroupChangeBusyException | IOException e) {
return GroupChangeResult.SUCCESS;
} catch (GroupChangeException | IOException e) {
Log.w(TAG, e);
return false;
return GroupChangeResult.failure(GroupChangeFailureReason.fromException(e));
}
}
private void handleLeaveGroupResult(boolean success) {
if (success) {
private void handleLeaveGroupResult(@NonNull GroupChangeResult result) {
if (result.isSuccess()) {
if (onSuccess != null) onSuccess.run();
} else {
Toast.makeText(activity, R.string.ConversationActivity_error_leaving_group, Toast.LENGTH_LONG).show();
Toast.makeText(activity, GroupErrors.getUserDisplayMessage(result.getFailureReason()), Toast.LENGTH_LONG).show();
}
}
}

View File

@ -5,12 +5,9 @@ import android.content.Context;
import androidx.annotation.NonNull;
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
import org.thoughtcrime.securesms.groups.GroupChangeBusyException;
import org.thoughtcrime.securesms.groups.GroupChangeFailedException;
import org.thoughtcrime.securesms.groups.GroupChangeException;
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.MembershipNotSuitableForV2Exception;
import org.thoughtcrime.securesms.groups.ui.GroupChangeErrorCallback;
import org.thoughtcrime.securesms.groups.ui.GroupChangeFailureReason;
@ -44,15 +41,9 @@ final class AddToGroupRepository {
GroupManager.addMembers(context, pushGroupId, Collections.singletonList(recipientId));
success.run();
} catch (GroupInsufficientRightsException | GroupNotAMemberException e) {
} catch (GroupChangeException | MembershipNotSuitableForV2Exception | IOException e) {
Log.w(TAG, e);
error.onError(GroupChangeFailureReason.NO_RIGHTS);
} catch (GroupChangeFailedException | GroupChangeBusyException | IOException e) {
Log.w(TAG, e);
error.onError(GroupChangeFailureReason.OTHER);
} catch (MembershipNotSuitableForV2Exception e) {
Log.w(TAG, e);
error.onError(GroupChangeFailureReason.NOT_CAPABLE);
error.onError(GroupChangeFailureReason.fromException(e));
}
});
}

View File

@ -20,10 +20,10 @@ import org.thoughtcrime.securesms.PassphraseRequiredActivity;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.groups.BadGroupIdException;
import org.thoughtcrime.securesms.groups.GroupId;
import org.thoughtcrime.securesms.groups.ui.GroupChangeResult;
import org.thoughtcrime.securesms.groups.ui.GroupErrors;
import org.thoughtcrime.securesms.groups.ui.GroupMemberEntry;
import org.thoughtcrime.securesms.groups.ui.GroupMemberListView;
import org.thoughtcrime.securesms.groups.ui.chooseadmin.ChooseNewAdminRepository.UpdateResult;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.util.DynamicNoActionBarTheme;
import org.thoughtcrime.securesms.util.DynamicTheme;
@ -108,7 +108,7 @@ public final class ChooseNewAdminActivity extends PassphraseRequiredActivity {
viewModel.getSelection().observe(this, selection -> done.setVisibility(selection.isEmpty() ? View.GONE : View.VISIBLE));
}
private void handleUpdateAndLeaveResult(@NonNull UpdateResult updateResult) {
private void handleUpdateAndLeaveResult(@NonNull GroupChangeResult updateResult) {
if (updateResult.isSuccess()) {
String title = Recipient.externalGroup(this, groupId).getDisplayName(this);
Toast.makeText(this, getString(R.string.ChooseNewAdminActivity_you_left, title), Toast.LENGTH_LONG).show();

View File

@ -3,60 +3,32 @@ package org.thoughtcrime.securesms.groups.ui.chooseadmin;
import android.app.Application;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.WorkerThread;
import androidx.core.util.Consumer;
import org.thoughtcrime.securesms.groups.GroupChangeBusyException;
import org.thoughtcrime.securesms.groups.GroupChangeFailedException;
import org.thoughtcrime.securesms.groups.GroupChangeException;
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.GroupChangeFailureReason;
import org.thoughtcrime.securesms.groups.ui.GroupChangeResult;
import org.thoughtcrime.securesms.recipients.RecipientId;
import java.io.IOException;
import java.util.List;
public final class ChooseNewAdminRepository {
private Application context;
private final Application context;
ChooseNewAdminRepository(@NonNull Application context) {
this.context = context;
}
@WorkerThread
@NonNull UpdateResult updateAdminsAndLeave(@NonNull GroupId.V2 groupId, @NonNull List<RecipientId> newAdminIds) {
@NonNull GroupChangeResult updateAdminsAndLeave(@NonNull GroupId.V2 groupId, @NonNull List<RecipientId> newAdminIds) {
try {
GroupManager.addMemberAdminsAndLeaveGroup(context, groupId, newAdminIds);
return new UpdateResult();
} catch (GroupInsufficientRightsException e) {
return new UpdateResult(GroupChangeFailureReason.NO_RIGHTS);
} catch (GroupNotAMemberException e) {
return new UpdateResult(GroupChangeFailureReason.NOT_A_MEMBER);
} catch (GroupChangeFailedException | GroupChangeBusyException | IOException e) {
return new UpdateResult(GroupChangeFailureReason.OTHER);
}
}
static final class UpdateResult {
final @Nullable GroupChangeFailureReason failureReason;
UpdateResult() {
this(null);
}
UpdateResult(@Nullable GroupChangeFailureReason failureReason) {
this.failureReason = failureReason;
}
boolean isSuccess() {
return failureReason == null;
}
@Nullable GroupChangeFailureReason getFailureReason() {
return failureReason;
return GroupChangeResult.SUCCESS;
} catch (GroupChangeException | IOException e) {
return GroupChangeResult.failure(GroupChangeFailureReason.fromException(e));
}
}
}

View File

@ -1,11 +1,9 @@
package org.thoughtcrime.securesms.groups.ui.chooseadmin;
import androidx.annotation.NonNull;
import androidx.annotation.StringRes;
import androidx.core.util.Consumer;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.Transformations;
import androidx.lifecycle.ViewModel;
import androidx.lifecycle.ViewModelProvider;
@ -14,13 +12,10 @@ import com.annimon.stream.Stream;
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
import org.thoughtcrime.securesms.groups.GroupId;
import org.thoughtcrime.securesms.groups.LiveGroup;
import org.thoughtcrime.securesms.groups.ui.GroupErrors;
import org.thoughtcrime.securesms.groups.ui.GroupChangeResult;
import org.thoughtcrime.securesms.groups.ui.GroupMemberEntry;
import org.thoughtcrime.securesms.groups.ui.chooseadmin.ChooseNewAdminRepository.UpdateResult;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientId;
import org.thoughtcrime.securesms.util.concurrent.SimpleTask;
import org.thoughtcrime.securesms.util.livedata.LiveDataUtil;
import java.util.Collections;
import java.util.List;
@ -53,7 +48,7 @@ final class ChooseNewAdminViewModel extends ViewModel {
this.selection.setValue(selection);
}
void updateAdminsAndLeave(@NonNull Consumer<UpdateResult> consumer) {
void updateAdminsAndLeave(@NonNull Consumer<GroupChangeResult> consumer) {
//noinspection ConstantConditions
List<RecipientId> recipientIds = Stream.of(selection.getValue()).map(entry -> entry.getMember().getId()).toList();
SimpleTask.run(() -> repository.updateAdminsAndLeave(groupId, recipientIds), consumer::accept);

View File

@ -8,7 +8,6 @@ import android.view.View;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
import com.annimon.stream.Stream;
@ -24,24 +23,14 @@ import org.thoughtcrime.securesms.logging.Log;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientId;
import org.thoughtcrime.securesms.util.FeatureFlags;
import org.thoughtcrime.securesms.util.ProfileUtil;
import org.thoughtcrime.securesms.util.Stopwatch;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.thoughtcrime.securesms.util.concurrent.SimpleTask;
import org.thoughtcrime.securesms.util.views.SimpleProgressDialog;
import org.whispersystems.libsignal.util.guava.Optional;
import org.whispersystems.signalservice.api.profiles.ProfileAndCredential;
import org.whispersystems.signalservice.api.profiles.SignalServiceProfile;
import org.whispersystems.signalservice.internal.util.concurrent.ListenableFuture;
import java.io.IOException;
import java.util.List;
import java.util.Locale;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicReference;
public class CreateGroupActivity extends ContactSelectionActivity {
@ -133,15 +122,8 @@ public class CreateGroupActivity extends ContactSelectionActivity {
}
private void handleNextPressed() {
Stopwatch stopwatch = new Stopwatch("Recipient Refresh");
AtomicReference<AlertDialog> progressDialog = new AtomicReference<>();
Runnable showDialogRunnable = () -> {
Log.i(TAG, "Taking some time. Showing a progress dialog.");
progressDialog.set(SimpleProgressDialog.show(this));
};
next.postDelayed(showDialogRunnable, 300);
Stopwatch stopwatch = new Stopwatch("Recipient Refresh");
SimpleProgressDialog.DismissibleDialog dismissibleDialog = SimpleProgressDialog.showDelayed(this);
SimpleTask.run(getLifecycle(), () -> {
RecipientId[] ids = Stream.of(contactsFragment.getSelectedContacts())
@ -182,11 +164,8 @@ public class CreateGroupActivity extends ContactSelectionActivity {
return ids;
}, ids -> {
if (progressDialog.get() != null) {
progressDialog.get().dismiss();
}
dismissibleDialog.dismiss();
next.removeCallbacks(showDialogRunnable);
stopwatch.stop(TAG);
startActivityForResult(AddGroupDetailsActivity.newIntent(this, ids), REQUEST_CODE_ADD_DETAILS);

View File

@ -9,7 +9,7 @@ import androidx.core.util.Consumer;
import com.annimon.stream.Stream;
import org.thoughtcrime.securesms.groups.GroupChangeBusyException;
import org.thoughtcrime.securesms.groups.GroupChangeFailedException;
import org.thoughtcrime.securesms.groups.GroupChangeException;
import org.thoughtcrime.securesms.groups.GroupManager;
import org.thoughtcrime.securesms.groups.ui.GroupMemberEntry;
import org.thoughtcrime.securesms.recipients.Recipient;
@ -57,7 +57,7 @@ final class AddGroupDetailsRepository {
resultConsumer.accept(GroupCreateResult.success(result));
} catch (GroupChangeBusyException e) {
resultConsumer.accept(GroupCreateResult.error(GroupCreateResult.Error.Type.ERROR_BUSY));
} catch (GroupChangeFailedException e) {
} catch (GroupChangeException e) {
resultConsumer.accept(GroupCreateResult.error(GroupCreateResult.Error.Type.ERROR_FAILED));
} catch (IOException e) {
resultConsumer.accept(GroupCreateResult.error(GroupCreateResult.Error.Type.ERROR_IO));

View File

@ -14,12 +14,9 @@ import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.database.GroupDatabase;
import org.thoughtcrime.securesms.database.ThreadDatabase;
import org.thoughtcrime.securesms.groups.GroupAccessControl;
import org.thoughtcrime.securesms.groups.GroupChangeBusyException;
import org.thoughtcrime.securesms.groups.GroupChangeFailedException;
import org.thoughtcrime.securesms.groups.GroupChangeException;
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.GroupProtoUtil;
import org.thoughtcrime.securesms.groups.MembershipNotSuitableForV2Exception;
import org.thoughtcrime.securesms.groups.ui.AddMembersResultCallback;
@ -89,15 +86,9 @@ final class ManageGroupRepository {
SignalExecutors.UNBOUNDED.execute(() -> {
try {
GroupManager.updateGroupTimer(context, groupId.requirePush(), newExpirationTime);
} catch (GroupInsufficientRightsException e) {
} catch (GroupChangeException | IOException e) {
Log.w(TAG, e);
error.onError(GroupChangeFailureReason.NO_RIGHTS);
} catch (GroupNotAMemberException e) {
Log.w(TAG, e);
error.onError(GroupChangeFailureReason.NOT_A_MEMBER);
} catch (GroupChangeFailedException | GroupChangeBusyException | IOException e) {
Log.w(TAG, e);
error.onError(GroupChangeFailureReason.OTHER);
error.onError(GroupChangeFailureReason.fromException(e));
}
});
}
@ -106,12 +97,9 @@ final class ManageGroupRepository {
SignalExecutors.UNBOUNDED.execute(() -> {
try {
GroupManager.applyMembershipAdditionRightsChange(context, groupId.requireV2(), newRights);
} catch (GroupInsufficientRightsException | GroupNotAMemberException e) {
} catch (GroupChangeException | IOException e) {
Log.w(TAG, e);
error.onError(GroupChangeFailureReason.NO_RIGHTS);
} catch (GroupChangeFailedException | GroupChangeBusyException | IOException e) {
Log.w(TAG, e);
error.onError(GroupChangeFailureReason.OTHER);
error.onError(GroupChangeFailureReason.fromException(e));
}
});
}
@ -120,12 +108,9 @@ final class ManageGroupRepository {
SignalExecutors.UNBOUNDED.execute(() -> {
try {
GroupManager.applyAttributesRightsChange(context, groupId.requireV2(), newRights);
} catch (GroupInsufficientRightsException | GroupNotAMemberException e) {
} catch (GroupChangeException | IOException e) {
Log.w(TAG, e);
error.onError(GroupChangeFailureReason.NO_RIGHTS);
} catch (GroupChangeFailedException | GroupChangeBusyException | IOException e) {
Log.w(TAG, e);
error.onError(GroupChangeFailureReason.OTHER);
error.onError(GroupChangeFailureReason.fromException(e));
}
});
}
@ -148,26 +133,21 @@ final class ManageGroupRepository {
try {
GroupManager.GroupActionResult groupActionResult = GroupManager.addMembers(context, groupId.requirePush(), selected);
addMembersResultCallback.onMembersAdded(groupActionResult.getAddedMemberCount(), groupActionResult.getInvitedMembers());
} catch (GroupInsufficientRightsException | GroupNotAMemberException e) {
} catch (GroupChangeException | MembershipNotSuitableForV2Exception | IOException e) {
Log.w(TAG, e);
error.onError(GroupChangeFailureReason.NO_RIGHTS);
} catch (GroupChangeFailedException | GroupChangeBusyException | IOException e) {
Log.w(TAG, e);
error.onError(GroupChangeFailureReason.OTHER);
} catch (MembershipNotSuitableForV2Exception e) {
Log.w(TAG, e);
error.onError(GroupChangeFailureReason.NOT_CAPABLE);
error.onError(GroupChangeFailureReason.fromException(e));
}
});
}
void blockAndLeaveGroup(@NonNull GroupChangeErrorCallback error) {
void blockAndLeaveGroup(@NonNull GroupChangeErrorCallback error, @NonNull Runnable onSuccess) {
SignalExecutors.UNBOUNDED.execute(() -> {
try {
RecipientUtil.block(context, Recipient.externalGroup(context, groupId));
} catch (GroupChangeFailedException | GroupChangeBusyException | IOException e) {
onSuccess.run();
} catch (GroupChangeException | IOException e) {
Log.w(TAG, e);
error.onError(GroupChangeFailureReason.OTHER);
error.onError(GroupChangeFailureReason.fromException(e));
}
});
}

View File

@ -40,6 +40,7 @@ import org.thoughtcrime.securesms.util.ExpirationUtil;
import org.thoughtcrime.securesms.util.SingleLiveEvent;
import org.thoughtcrime.securesms.util.Util;
import org.thoughtcrime.securesms.util.livedata.LiveDataUtil;
import org.thoughtcrime.securesms.util.views.SimpleProgressDialog;
import java.util.ArrayList;
import java.util.List;
@ -213,7 +214,7 @@ public class ManageGroupViewModel extends ViewModel {
manageGroupRepository.getRecipient(recipient -> BlockUnblockDialog.showBlockFor(activity,
activity.getLifecycle(),
recipient,
() -> manageGroupRepository.blockAndLeaveGroup(this::showErrorToast)));
this::onBlockAndLeaveConfirmed));
}
void unblock(@NonNull FragmentActivity activity) {
@ -237,6 +238,16 @@ public class ManageGroupViewModel extends ViewModel {
memberListCollapseState.setValue(CollapseState.OPEN);
}
private void onBlockAndLeaveConfirmed() {
SimpleProgressDialog.DismissibleDialog dismissibleDialog = SimpleProgressDialog.showDelayed(context);
manageGroupRepository.blockAndLeaveGroup(e -> {
dismissibleDialog.dismiss();
showErrorToast(e);
},
dismissibleDialog::dismiss);
}
private static @NonNull List<GroupMemberEntry.FullMember> filterMemberList(@NonNull List<GroupMemberEntry.FullMember> members,
@NonNull CollapseState collapseState)
{

View File

@ -16,12 +16,9 @@ import org.signal.zkgroup.groups.UuidCiphertext;
import org.signal.zkgroup.util.UUIDUtil;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.database.GroupDatabase;
import org.thoughtcrime.securesms.groups.GroupChangeBusyException;
import org.thoughtcrime.securesms.groups.GroupChangeFailedException;
import org.thoughtcrime.securesms.groups.GroupChangeException;
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.GroupProtoUtil;
import org.thoughtcrime.securesms.logging.Log;
import org.thoughtcrime.securesms.recipients.Recipient;
@ -105,7 +102,7 @@ final class PendingMemberRepository {
try {
GroupManager.cancelInvites(context, groupId, uuidCipherTexts);
return true;
} catch (GroupChangeFailedException | GroupInsufficientRightsException | IOException | GroupNotAMemberException | GroupChangeBusyException e) {
} catch (GroupChangeException | IOException e) {
Log.w(TAG, e);
return false;
}

View File

@ -12,11 +12,8 @@ import org.thoughtcrime.securesms.database.MessagingDatabase;
import org.thoughtcrime.securesms.database.RecipientDatabase;
import org.thoughtcrime.securesms.database.ThreadDatabase;
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
import org.thoughtcrime.securesms.groups.GroupChangeBusyException;
import org.thoughtcrime.securesms.groups.GroupChangeFailedException;
import org.thoughtcrime.securesms.groups.GroupInsufficientRightsException;
import org.thoughtcrime.securesms.groups.GroupChangeException;
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.jobs.MultiDeviceMessageRequestResponseJob;
@ -101,12 +98,9 @@ final class MessageRequestRepository {
recipientDatabase.setProfileSharing(liveRecipient.getId(), true);
onMessageRequestAccepted.run();
} catch (GroupInsufficientRightsException e) {
} catch (GroupChangeException | IOException e) {
Log.w(TAG, e);
error.onError(GroupChangeFailureReason.NO_RIGHTS);
} catch (GroupChangeBusyException | GroupChangeFailedException | GroupNotAMemberException | IOException e) {
Log.w(TAG, e);
error.onError(GroupChangeFailureReason.OTHER);
error.onError(GroupChangeFailureReason.fromException(e));
}
} else {
RecipientDatabase recipientDatabase = DatabaseFactory.getRecipientDatabase(context);
@ -139,9 +133,9 @@ final class MessageRequestRepository {
if (resolved.isGroup() && resolved.requireGroupId().isPush()) {
try {
GroupManager.leaveGroupFromBlockOrMessageRequest(context, resolved.requireGroupId().requirePush());
} catch (GroupChangeBusyException | GroupChangeFailedException | IOException e) {
} catch (GroupChangeException | IOException e) {
Log.w(TAG, e);
error.onError(GroupChangeFailureReason.OTHER);
error.onError(GroupChangeFailureReason.fromException(e));
return;
}
}
@ -165,8 +159,9 @@ final class MessageRequestRepository {
Recipient recipient = liveRecipient.resolve();
try {
RecipientUtil.block(context, recipient);
} catch (GroupChangeBusyException | GroupChangeFailedException | IOException e) {
error.onError(GroupChangeFailureReason.OTHER);
} catch (GroupChangeException | IOException e) {
Log.w(TAG, e);
error.onError(GroupChangeFailureReason.fromException(e));
return;
}
liveRecipient.refresh();
@ -188,8 +183,9 @@ final class MessageRequestRepository {
Recipient recipient = liveRecipient.resolve();
try{
RecipientUtil.block(context, recipient);
} catch (GroupChangeBusyException | GroupChangeFailedException | IOException e) {
error.onError(GroupChangeFailureReason.OTHER);
} catch (GroupChangeException | IOException e) {
Log.w(TAG, e);
error.onError(GroupChangeFailureReason.fromException(e));
return;
}
liveRecipient.refresh();

View File

@ -8,12 +8,9 @@ import androidx.annotation.WorkerThread;
import androidx.core.util.Consumer;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.groups.GroupChangeBusyException;
import org.thoughtcrime.securesms.groups.GroupChangeFailedException;
import org.thoughtcrime.securesms.groups.GroupChangeException;
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.logging.Log;
import org.thoughtcrime.securesms.profiles.AvatarHelper;
import org.thoughtcrime.securesms.profiles.ProfileName;
@ -83,7 +80,7 @@ class EditPushGroupProfileRepository implements EditProfileRepository {
GroupManager.updateGroupDetails(context, groupId, avatar, avatarChanged, displayName, displayNameChanged);
return UploadResult.SUCCESS;
} catch (GroupChangeFailedException | GroupInsufficientRightsException | IOException | GroupNotAMemberException | GroupChangeBusyException e) {
} catch (GroupChangeException | IOException e) {
return UploadResult.ERROR_IO;
}

View File

@ -14,6 +14,7 @@ import org.thoughtcrime.securesms.database.RecipientDatabase.RegisteredState;
import org.thoughtcrime.securesms.database.ThreadDatabase;
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
import org.thoughtcrime.securesms.groups.GroupChangeBusyException;
import org.thoughtcrime.securesms.groups.GroupChangeException;
import org.thoughtcrime.securesms.groups.GroupChangeFailedException;
import org.thoughtcrime.securesms.groups.GroupManager;
import org.thoughtcrime.securesms.jobs.DirectoryRefreshJob;
@ -77,7 +78,7 @@ public class RecipientUtil {
try {
block(context, recipient);
} catch (GroupChangeBusyException | IOException | GroupChangeFailedException e) {
} catch (GroupChangeException | IOException e) {
throw new AssertionError(e);
}
}

View File

@ -10,12 +10,9 @@ import org.thoughtcrime.securesms.contacts.sync.DirectoryHelper;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.database.GroupDatabase;
import org.thoughtcrime.securesms.database.IdentityDatabase;
import org.thoughtcrime.securesms.groups.GroupChangeBusyException;
import org.thoughtcrime.securesms.groups.GroupChangeFailedException;
import org.thoughtcrime.securesms.groups.GroupChangeException;
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;
@ -89,12 +86,9 @@ final class RecipientDialogRepository {
try {
GroupManager.ejectFromGroup(context, Objects.requireNonNull(groupId).requireV2(), Recipient.resolved(recipientId));
return true;
} catch (GroupInsufficientRightsException | GroupNotAMemberException e) {
} catch (GroupChangeException | IOException e) {
Log.w(TAG, e);
error.onError(GroupChangeFailureReason.NO_RIGHTS);
} catch (GroupChangeFailedException | GroupChangeBusyException | IOException e) {
Log.w(TAG, e);
error.onError(GroupChangeFailureReason.OTHER);
error.onError(GroupChangeFailureReason.fromException(e));
}
return false;
},
@ -107,12 +101,9 @@ final class RecipientDialogRepository {
try {
GroupManager.setMemberAdmin(context, Objects.requireNonNull(groupId).requireV2(), recipientId, admin);
return true;
} catch (GroupInsufficientRightsException | GroupNotAMemberException e) {
} catch (GroupChangeException | IOException e) {
Log.w(TAG, e);
error.onError(GroupChangeFailureReason.NO_RIGHTS);
} catch (GroupChangeFailedException | GroupChangeBusyException | IOException e) {
Log.w(TAG, e);
error.onError(GroupChangeFailureReason.OTHER);
error.onError(GroupChangeFailureReason.fromException(e));
}
return false;
},

View File

@ -2,18 +2,27 @@ package org.thoughtcrime.securesms.util.views;
import android.content.Context;
import androidx.annotation.AnyThread;
import androidx.annotation.MainThread;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.logging.Log;
import org.thoughtcrime.securesms.util.Util;
import java.util.concurrent.atomic.AtomicReference;
/**
* Helper class to show a fullscreen blocking indeterminate progress dialog.
*/
public final class SimpleProgressDialog {
private static final String TAG = Log.tag(SimpleProgressDialog.class);
private SimpleProgressDialog() {}
@MainThread
public static @NonNull AlertDialog show(@NonNull Context context) {
AlertDialog dialog = new AlertDialog.Builder(context)
.setView(R.layout.progress_dialog)
@ -25,4 +34,44 @@ public final class SimpleProgressDialog {
return dialog;
}
@AnyThread
public static @NonNull DismissibleDialog showDelayed(@NonNull Context context) {
return showDelayed(context, 300);
}
/**
* Shows the dialog after {@param delayMs} ms.
* <p>
* To dismiss, call {@link DismissibleDialog#dismiss()} on the result. If dismiss is called before
* the delay has elapsed, the dialog will not show at all.
* <p>
* Dismiss can be called on any thread.
*/
@AnyThread
public static @NonNull DismissibleDialog showDelayed(@NonNull Context context, int delayMs) {
AtomicReference<AlertDialog> dialogAtomicReference = new AtomicReference<>();
Runnable showRunnable = () -> {
Log.i(TAG, "Taking some time. Showing a progress dialog.");
dialogAtomicReference.set(show(context));
};
Util.runOnMainDelayed(showRunnable, delayMs);
return () -> {
Util.cancelRunnableOnMain(showRunnable);
Util.runOnMain(() -> {
AlertDialog alertDialog = dialogAtomicReference.getAndSet(null);
if (alertDialog != null) {
alertDialog.dismiss();
}
});
};
}
public interface DismissibleDialog {
@AnyThread
void dismiss();
}
}

View File

@ -234,7 +234,6 @@
<string name="ConversationActivity_transport_insecure_mms">Insecure MMS</string>
<string name="ConversationActivity_transport_signal">Signal</string>
<string name="ConversationActivity_lets_switch_to_signal">Let\'s switch to Signal %1$s</string>
<string name="ConversationActivity_error_leaving_group">Error leaving group</string>
<string name="ConversationActivity_specify_recipient">Please choose a contact</string>
<string name="ConversationActivity_unblock_this_contact_question">Unblock this contact?</string>
<string name="ConversationActivity_unblock_this_group_question">Unblock this group?</string>
@ -554,6 +553,8 @@
<string name="ManageGroupActivity_not_capable">Someone you added does not support new groups and needs to update Signal</string>
<string name="ManageGroupActivity_failed_to_update_the_group">Failed to update the group</string>
<string name="ManageGroupActivity_youre_not_a_member_of_the_group">You\'re not a member of the group</string>
<string name="ManageGroupActivity_failed_to_update_the_group_please_retry_later">Failed to update the group please retry later</string>
<string name="ManageGroupActivity_failed_to_update_the_group_due_to_a_network_error_please_retry_later">Failed to update the group due to a network error, please retry later</string>
<string name="ManageGroupActivity_edit_name_and_picture">Edit name and picture</string>