mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-02-20 17:57:29 +00:00
Enable split pane UI for add group members screen.
This commit is contained in:
committed by
Cody Henthorne
parent
c851387f57
commit
94241f7068
@@ -66,7 +66,6 @@ import org.thoughtcrime.securesms.components.settings.conversation.preferences.L
|
||||
import org.thoughtcrime.securesms.components.settings.conversation.preferences.RecipientPreference
|
||||
import org.thoughtcrime.securesms.components.settings.conversation.preferences.SharedMediaPreference
|
||||
import org.thoughtcrime.securesms.components.settings.conversation.preferences.Utils.formatMutedUntil
|
||||
import org.thoughtcrime.securesms.contacts.ContactSelectionDisplayMode
|
||||
import org.thoughtcrime.securesms.conversation.ConversationIntents
|
||||
import org.thoughtcrime.securesms.database.AttachmentTable
|
||||
import org.thoughtcrime.securesms.groups.GroupId
|
||||
@@ -953,11 +952,7 @@ class ConversationSettingsFragment : DSLSettingsFragment(
|
||||
startActivityForResult(
|
||||
AddMembersActivity.createIntent(
|
||||
requireContext(),
|
||||
addMembersToGroup.groupId,
|
||||
ContactSelectionDisplayMode.FLAG_PUSH,
|
||||
addMembersToGroup.selectionLimits.recommendedLimit,
|
||||
addMembersToGroup.selectionLimits.hardLimit,
|
||||
addMembersToGroup.groupMembersWithoutSelf
|
||||
addMembersToGroup
|
||||
),
|
||||
REQUEST_CODE_ADD_MEMBERS_TO_GROUP
|
||||
)
|
||||
|
||||
@@ -1,199 +0,0 @@
|
||||
package org.thoughtcrime.securesms.groups.ui.addmembers;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.activity.result.ActivityResultLauncher;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.lifecycle.ViewModelProvider;
|
||||
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||
|
||||
import org.signal.core.util.DimensionUnit;
|
||||
import org.signal.core.util.concurrent.SimpleTask;
|
||||
import org.thoughtcrime.securesms.ContactSelectionActivity;
|
||||
import org.thoughtcrime.securesms.ContactSelectionListFragment;
|
||||
import org.thoughtcrime.securesms.PushContactSelectionActivity;
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.contacts.paged.ChatType;
|
||||
import org.thoughtcrime.securesms.contacts.selection.ContactSelectionArguments;
|
||||
import org.thoughtcrime.securesms.groups.GroupId;
|
||||
import org.thoughtcrime.securesms.groups.SelectionLimits;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientRepository;
|
||||
import org.thoughtcrime.securesms.recipients.ui.findby.FindByActivity;
|
||||
import org.thoughtcrime.securesms.recipients.ui.findby.FindByMode;
|
||||
import org.thoughtcrime.securesms.util.Util;
|
||||
import org.thoughtcrime.securesms.util.views.SimpleProgressDialog;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public class AddMembersActivity extends PushContactSelectionActivity implements ContactSelectionListFragment.FindByCallback {
|
||||
|
||||
public static final String GROUP_ID = "group_id";
|
||||
|
||||
private View done;
|
||||
private AddMembersViewModel viewModel;
|
||||
private ActivityResultLauncher<FindByMode> findByActivityLauncher;
|
||||
|
||||
public static @NonNull Intent createIntent(@NonNull Context context,
|
||||
@NonNull GroupId groupId,
|
||||
int displayModeFlags,
|
||||
int selectionWarning,
|
||||
int selectionLimit,
|
||||
@NonNull List<RecipientId> membersWithoutSelf) {
|
||||
Intent intent = new Intent(context, AddMembersActivity.class);
|
||||
intent.putExtra(GROUP_ID, groupId.toString());
|
||||
intent.putExtra(ContactSelectionArguments.DISPLAY_MODE, displayModeFlags);
|
||||
intent.putExtra(ContactSelectionArguments.SELECTION_LIMITS, new SelectionLimits(selectionWarning, selectionLimit));
|
||||
intent.putParcelableArrayListExtra(ContactSelectionArguments.CURRENT_SELECTION, new ArrayList<>(membersWithoutSelf));
|
||||
intent.putExtra(ContactSelectionArguments.RV_PADDING_BOTTOM, (int) DimensionUnit.DP.toPixels(64f));
|
||||
intent.putExtra(ContactSelectionArguments.RV_CLIP, false);
|
||||
|
||||
return intent;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle icicle, boolean ready) {
|
||||
getIntent().putExtra(ContactSelectionActivity.EXTRA_LAYOUT_RES_ID, R.layout.add_members_activity);
|
||||
super.onCreate(icicle, ready);
|
||||
|
||||
AddMembersViewModel.Factory factory = new AddMembersViewModel.Factory(getGroupId());
|
||||
|
||||
done = findViewById(R.id.done);
|
||||
viewModel = new ViewModelProvider(this, factory).get(AddMembersViewModel.class);
|
||||
|
||||
done.setOnClickListener(v ->
|
||||
viewModel.getDialogStateForSelectedContacts(contactsFragment.getSelectedContacts(), this::displayAlertMessage)
|
||||
);
|
||||
|
||||
disableDone();
|
||||
|
||||
findByActivityLauncher = registerForActivityResult(new FindByActivity.Contract(), result -> {
|
||||
if (result != null) {
|
||||
contactsFragment.addRecipientToSelectionIfAble(result);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initializeToolbar() {
|
||||
getToolbar().setNavigationIcon(R.drawable.symbol_arrow_start_24);
|
||||
getToolbar().setNavigationOnClickListener(v -> {
|
||||
setResult(RESULT_CANCELED);
|
||||
finish();
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBeforeContactSelected(boolean isFromUnknownSearchKey, @NonNull Optional<RecipientId> recipientId, String number, @NonNull Optional<ChatType> chatType, @NonNull Consumer<Boolean> callback) {
|
||||
if (getGroupId().isV1() && recipientId.isPresent() && !Recipient.resolved(recipientId.get()).getHasE164()) {
|
||||
Toast.makeText(this, R.string.AddMembersActivity__this_person_cant_be_added_to_legacy_groups, Toast.LENGTH_SHORT).show();
|
||||
callback.accept(false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (contactsFragment.hasQueryFilter()) {
|
||||
getContactFilterView().clear();
|
||||
}
|
||||
|
||||
if (recipientId.isPresent()) {
|
||||
callback.accept(true);
|
||||
enableDone();
|
||||
return;
|
||||
}
|
||||
|
||||
AlertDialog progress = SimpleProgressDialog.show(this);
|
||||
|
||||
SimpleTask.run(getLifecycle(), () -> RecipientRepository.lookupNewE164(number), result -> {
|
||||
progress.dismiss();
|
||||
|
||||
if (result instanceof RecipientRepository.LookupResult.Success) {
|
||||
enableDone();
|
||||
callback.accept(true);
|
||||
} else if (result instanceof RecipientRepository.PhoneLookupResult.NotFound || result instanceof RecipientRepository.PhoneLookupResult.InvalidPhone) {
|
||||
new MaterialAlertDialogBuilder(this)
|
||||
.setMessage(getString(R.string.RecipientLookup_error__s_is_not_a_signal_user, number))
|
||||
.setPositiveButton(android.R.string.ok, null)
|
||||
.show();
|
||||
callback.accept(false);
|
||||
} else {
|
||||
new MaterialAlertDialogBuilder(this)
|
||||
.setMessage(R.string.NetworkFailure__network_error_check_your_connection_and_try_again)
|
||||
.setPositiveButton(android.R.string.ok, null)
|
||||
.show();
|
||||
callback.accept(false);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onContactDeselected(@NonNull Optional<RecipientId> recipientId, String number, @NonNull Optional<ChatType> chatType) {
|
||||
if (contactsFragment.hasQueryFilter()) {
|
||||
getContactFilterView().clear();
|
||||
}
|
||||
|
||||
if (contactsFragment.getSelectedContactsCount() < 1) {
|
||||
disableDone();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSelectionChanged() {
|
||||
int selectedContactsCount = contactsFragment.getTotalMemberCount() + 1;
|
||||
if (selectedContactsCount == 0) {
|
||||
getToolbar().setTitle(getString(R.string.AddMembersActivity__add_members));
|
||||
} else {
|
||||
getToolbar().setTitle(getResources().getQuantityString(R.plurals.CreateGroupActivity__d_members, selectedContactsCount, selectedContactsCount));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFindByPhoneNumber() {
|
||||
findByActivityLauncher.launch(FindByMode.PHONE_NUMBER);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFindByUsername() {
|
||||
findByActivityLauncher.launch(FindByMode.USERNAME);
|
||||
}
|
||||
|
||||
private void enableDone() {
|
||||
done.setEnabled(true);
|
||||
done.animate().alpha(1f);
|
||||
}
|
||||
|
||||
private void disableDone() {
|
||||
done.setEnabled(false);
|
||||
done.animate().alpha(0.5f);
|
||||
}
|
||||
|
||||
private GroupId getGroupId() {
|
||||
return GroupId.parseOrThrow(getIntent().getStringExtra(GROUP_ID));
|
||||
}
|
||||
|
||||
private void displayAlertMessage(@NonNull AddMembersViewModel.AddMemberDialogMessageState state) {
|
||||
Recipient recipient = Util.firstNonNull(state.getRecipient(), Recipient.UNKNOWN);
|
||||
|
||||
String message = getResources().getQuantityString(R.plurals.AddMembersActivity__add_d_members_to_s, state.getSelectionCount(),
|
||||
recipient.getDisplayName(this), state.getGroupTitle(), state.getSelectionCount());
|
||||
|
||||
new MaterialAlertDialogBuilder(this)
|
||||
.setMessage(message)
|
||||
.setNegativeButton(android.R.string.cancel, (dialog, which) -> dialog.cancel())
|
||||
.setPositiveButton(R.string.AddMembersActivity__add, (dialog, which) -> {
|
||||
dialog.dismiss();
|
||||
onFinishedSelection();
|
||||
})
|
||||
.setCancelable(true)
|
||||
.show();
|
||||
}
|
||||
}
|
||||
@@ -64,7 +64,7 @@ import java.text.NumberFormat
|
||||
/**
|
||||
* Allows members to be added to an existing Signal group by selecting from a list of recipients.
|
||||
*/
|
||||
class AddMembersActivityV2 : PassphraseRequiredActivity() {
|
||||
class AddMembersActivity : PassphraseRequiredActivity() {
|
||||
companion object {
|
||||
private const val EXTRA_GROUP_ID = "group_id"
|
||||
private const val EXTRA_SELECTION_LIMITS = "selection_limits"
|
||||
@@ -74,7 +74,7 @@ class AddMembersActivityV2 : PassphraseRequiredActivity() {
|
||||
context: Context,
|
||||
event: ConversationSettingsEvent.AddMembersToGroup
|
||||
): Intent {
|
||||
return Intent(context, AddMembersActivityV2::class.java).apply {
|
||||
return Intent(context, AddMembersActivity::class.java).apply {
|
||||
putExtra(EXTRA_GROUP_ID, event.groupId)
|
||||
putExtra(EXTRA_SELECTION_LIMITS, event.selectionLimits)
|
||||
putParcelableArrayListExtra(EXTRA_PRESELECTED_RECIPIENTS, ArrayList(event.groupMembersWithoutSelf))
|
||||
@@ -90,7 +90,7 @@ class AddMembersActivityV2 : PassphraseRequiredActivity() {
|
||||
SignalTheme {
|
||||
AddMembersScreen(
|
||||
viewModel = viewModel {
|
||||
AddMembersViewModelV2(
|
||||
AddMembersViewModel(
|
||||
groupId = intent.getParcelableExtraCompat(EXTRA_GROUP_ID, GroupId::class.java)!!,
|
||||
existingMembersMinusSelf = intent.getParcelableArrayListExtraCompat(EXTRA_PRESELECTED_RECIPIENTS, RecipientId::class.java)!!.toSet(),
|
||||
selectionLimits = intent.getParcelableExtraCompat(EXTRA_SELECTION_LIMITS, SelectionLimits::class.java)!!
|
||||
@@ -109,7 +109,7 @@ class AddMembersActivityV2 : PassphraseRequiredActivity() {
|
||||
|
||||
@Composable
|
||||
private fun AddMembersScreen(
|
||||
viewModel: AddMembersViewModelV2,
|
||||
viewModel: AddMembersViewModel,
|
||||
activityIntent: Intent,
|
||||
closeScreen: (result: ActivityResult) -> Unit
|
||||
) {
|
||||
@@ -294,7 +294,7 @@ private fun GroupAddConfirmationDialog(
|
||||
val bodyText: String = when (message) {
|
||||
is UserMessage.ConfirmAddMember -> {
|
||||
stringResource(
|
||||
id = R.string.AddMembersActivityV2__add_member_to_s,
|
||||
id = R.string.AddMembersActivity__add_member_to_s,
|
||||
message.recipient.getDisplayName(context),
|
||||
message.group.getDisplayTitle(context)
|
||||
)
|
||||
@@ -302,7 +302,7 @@ private fun GroupAddConfirmationDialog(
|
||||
|
||||
is UserMessage.ConfirmAddMembers -> {
|
||||
pluralStringResource(
|
||||
id = R.plurals.AddMembersActivityV2__add_d_members_to_s,
|
||||
id = R.plurals.AddMembersActivity__add_d_members_to_s,
|
||||
message.recipientIds.size,
|
||||
message.recipientIds.size,
|
||||
message.group.getDisplayTitle(context)
|
||||
@@ -1,33 +0,0 @@
|
||||
package org.thoughtcrime.securesms.groups.ui.addmembers;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.WorkerThread;
|
||||
|
||||
import org.thoughtcrime.securesms.contacts.SelectedContact;
|
||||
import org.thoughtcrime.securesms.database.SignalDatabase;
|
||||
import org.thoughtcrime.securesms.dependencies.AppDependencies;
|
||||
import org.thoughtcrime.securesms.groups.GroupId;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||
|
||||
final class AddMembersRepository {
|
||||
|
||||
private final Context context;
|
||||
private final GroupId groupId;
|
||||
|
||||
AddMembersRepository(@NonNull GroupId groupId) {
|
||||
this.groupId = groupId;
|
||||
this.context = AppDependencies.getApplication();
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
RecipientId getOrCreateRecipientId(@NonNull SelectedContact selectedContact) {
|
||||
return selectedContact.getOrCreateRecipientId();
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
String getGroupTitle() {
|
||||
return SignalDatabase.groups().requireGroup(groupId).getTitle();
|
||||
}
|
||||
}
|
||||
@@ -1,114 +0,0 @@
|
||||
package org.thoughtcrime.securesms.groups.ui.addmembers;
|
||||
|
||||
import android.text.TextUtils;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.WorkerThread;
|
||||
import androidx.core.util.Consumer;
|
||||
import androidx.lifecycle.ViewModel;
|
||||
import androidx.lifecycle.ViewModelProvider;
|
||||
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.contacts.SelectedContact;
|
||||
import org.thoughtcrime.securesms.dependencies.AppDependencies;
|
||||
import org.thoughtcrime.securesms.groups.GroupId;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||
import org.signal.core.util.concurrent.SimpleTask;
|
||||
import org.whispersystems.signalservice.api.util.Preconditions;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
public final class AddMembersViewModel extends ViewModel {
|
||||
|
||||
private final AddMembersRepository repository;
|
||||
|
||||
private AddMembersViewModel(@NonNull GroupId groupId) {
|
||||
this.repository = new AddMembersRepository(groupId);
|
||||
}
|
||||
|
||||
void getDialogStateForSelectedContacts(@NonNull List<SelectedContact> selectedContacts,
|
||||
@NonNull Consumer<AddMemberDialogMessageState> callback)
|
||||
{
|
||||
SimpleTask.run(
|
||||
() -> {
|
||||
AddMemberDialogMessageStatePartial partialState = selectedContacts.size() == 1 ? getDialogStateForSingleRecipient(selectedContacts.get(0))
|
||||
: getDialogStateForMultipleRecipients(selectedContacts.size());
|
||||
|
||||
return new AddMemberDialogMessageState(partialState.recipientId == null ? Recipient.UNKNOWN : Recipient.resolved(partialState.recipientId),
|
||||
partialState.memberCount, titleOrDefault(repository.getGroupTitle()));
|
||||
},
|
||||
callback::accept
|
||||
);
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
private AddMemberDialogMessageStatePartial getDialogStateForSingleRecipient(@NonNull SelectedContact selectedContact) {
|
||||
return new AddMemberDialogMessageStatePartial(repository.getOrCreateRecipientId(selectedContact));
|
||||
}
|
||||
|
||||
private AddMemberDialogMessageStatePartial getDialogStateForMultipleRecipients(int recipientCount) {
|
||||
return new AddMemberDialogMessageStatePartial(recipientCount);
|
||||
}
|
||||
|
||||
private static @NonNull String titleOrDefault(@Nullable String title) {
|
||||
return TextUtils.isEmpty(title) ? AppDependencies.getApplication().getString(R.string.Recipient_unknown)
|
||||
: Objects.requireNonNull(title);
|
||||
}
|
||||
|
||||
private static final class AddMemberDialogMessageStatePartial {
|
||||
private final RecipientId recipientId;
|
||||
private final int memberCount;
|
||||
|
||||
private AddMemberDialogMessageStatePartial(@NonNull RecipientId recipientId) {
|
||||
this.recipientId = recipientId;
|
||||
this.memberCount = 1;
|
||||
}
|
||||
|
||||
private AddMemberDialogMessageStatePartial(int memberCount) {
|
||||
Preconditions.checkArgument(memberCount > 1);
|
||||
this.memberCount = memberCount;
|
||||
this.recipientId = null;
|
||||
}
|
||||
}
|
||||
|
||||
public static final class AddMemberDialogMessageState {
|
||||
private final Recipient recipient;
|
||||
private final String groupTitle;
|
||||
private final int selectionCount;
|
||||
|
||||
private AddMemberDialogMessageState(@Nullable Recipient recipient, int selectionCount, @NonNull String groupTitle) {
|
||||
this.recipient = recipient;
|
||||
this.groupTitle = groupTitle;
|
||||
this.selectionCount = selectionCount;
|
||||
}
|
||||
|
||||
public Recipient getRecipient() {
|
||||
return recipient;
|
||||
}
|
||||
|
||||
public int getSelectionCount() {
|
||||
return selectionCount;
|
||||
}
|
||||
|
||||
public @NonNull String getGroupTitle() {
|
||||
return groupTitle;
|
||||
}
|
||||
}
|
||||
|
||||
public static class Factory implements ViewModelProvider.Factory {
|
||||
|
||||
private final GroupId groupId;
|
||||
|
||||
public Factory(@NonNull GroupId groupId) {
|
||||
this.groupId = groupId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
|
||||
return Objects.requireNonNull(modelClass.cast(new AddMembersViewModel(groupId)));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -28,7 +28,7 @@ import org.thoughtcrime.securesms.recipients.RecipientRepository
|
||||
import org.thoughtcrime.securesms.recipients.ui.RecipientSelection
|
||||
import kotlin.collections.plus
|
||||
|
||||
class AddMembersViewModelV2(
|
||||
class AddMembersViewModel(
|
||||
private val groupId: GroupId,
|
||||
existingMembersMinusSelf: Set<RecipientId>,
|
||||
selectionLimits: SelectionLimits
|
||||
Reference in New Issue
Block a user