From d903bcf2b15327c387474f237a9dbe9d2980ba94 Mon Sep 17 00:00:00 2001 From: jeffrey-signal Date: Thu, 23 Oct 2025 11:01:55 -0400 Subject: [PATCH] Enable split pane UI for create group screen. --- app/src/main/AndroidManifest.xml | 6 +- .../thoughtcrime/securesms/MainActivity.kt | 2 +- .../thoughtcrime/securesms/MainNavigator.java | 3 +- .../conversation/NewConversationActivity.kt | 2 +- .../ui/creategroup/CreateGroupActivity.java | 239 ------------------ ...upActivityV2.kt => CreateGroupActivity.kt} | 6 +- .../megaphone/OnboardingMegaphone.kt | 2 +- .../main/res/layout/create_group_activity.xml | 69 ----- 8 files changed, 8 insertions(+), 321 deletions(-) delete mode 100644 app/src/main/java/org/thoughtcrime/securesms/groups/ui/creategroup/CreateGroupActivity.java rename app/src/main/java/org/thoughtcrime/securesms/groups/ui/creategroup/{CreateGroupActivityV2.kt => CreateGroupActivity.kt} (99%) delete mode 100644 app/src/main/res/layout/create_group_activity.xml diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index c697cddd73..f42b55a6b5 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -1055,12 +1055,8 @@ android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize" android:exported="false"/> - - diff --git a/app/src/main/java/org/thoughtcrime/securesms/MainActivity.kt b/app/src/main/java/org/thoughtcrime/securesms/MainActivity.kt index 0900e95a48..00f516eb2d 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/MainActivity.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/MainActivity.kt @@ -973,7 +973,7 @@ class MainActivity : PassphraseRequiredActivity(), VoiceNoteMediaControllerOwner inner class ToolbarCallback : MainToolbarCallback { override fun onNewGroupClick() { - startActivity(CreateGroupActivity.newIntent(this@MainActivity)) + startActivity(CreateGroupActivity.createIntent(this@MainActivity)) } override fun onClearPassphraseClick() { diff --git a/app/src/main/java/org/thoughtcrime/securesms/MainNavigator.java b/app/src/main/java/org/thoughtcrime/securesms/MainNavigator.java index 1e47176372..5a0f1b76a1 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/MainNavigator.java +++ b/app/src/main/java/org/thoughtcrime/securesms/MainNavigator.java @@ -1,7 +1,6 @@ package org.thoughtcrime.securesms; import android.app.Activity; -import android.content.Intent; import androidx.annotation.NonNull; import androidx.appcompat.app.AppCompatActivity; @@ -56,7 +55,7 @@ public class MainNavigator { } public void goToGroupCreation() { - activity.startActivity(CreateGroupActivity.newIntent(activity)); + activity.startActivity(CreateGroupActivity.createIntent(activity)); } private @NonNull FragmentManager getFragmentManager() { diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/NewConversationActivity.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/NewConversationActivity.kt index 69cda962f4..670e10ec82 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/NewConversationActivity.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/NewConversationActivity.kt @@ -128,7 +128,7 @@ private fun NewConversationScreen( val callbacks = remember { object : UiCallbacks { override fun onSearchQueryChanged(query: String) = viewModel.onSearchQueryChanged(query) - override fun onCreateNewGroup() = createGroupLauncher.launch(CreateGroupActivity.newIntent(context)) + override fun onCreateNewGroup() = createGroupLauncher.launch(CreateGroupActivity.createIntent(context)) override fun onFindByUsername() = findByLauncher.launch(FindByMode.USERNAME) override fun onFindByPhoneNumber() = findByLauncher.launch(FindByMode.PHONE_NUMBER) override suspend fun shouldAllowSelection(id: RecipientId?, phone: PhoneNumber?): Boolean = true diff --git a/app/src/main/java/org/thoughtcrime/securesms/groups/ui/creategroup/CreateGroupActivity.java b/app/src/main/java/org/thoughtcrime/securesms/groups/ui/creategroup/CreateGroupActivity.java deleted file mode 100644 index 1d0cc0847f..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/groups/ui/creategroup/CreateGroupActivity.java +++ /dev/null @@ -1,239 +0,0 @@ -package org.thoughtcrime.securesms.groups.ui.creategroup; - -import android.content.Context; -import android.content.Intent; -import android.os.Bundle; -import android.view.MenuItem; -import android.view.View; - -import androidx.activity.result.ActivityResultLauncher; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.appcompat.app.AlertDialog; - -import com.google.android.material.button.MaterialButton; -import com.google.android.material.dialog.MaterialAlertDialogBuilder; -import com.google.android.material.floatingactionbutton.FloatingActionButton; - -import org.signal.core.util.DimensionUnit; -import org.signal.core.util.Stopwatch; -import org.signal.core.util.concurrent.SimpleTask; -import org.signal.core.util.logging.Log; -import org.thoughtcrime.securesms.ContactSelectionActivity; -import org.thoughtcrime.securesms.ContactSelectionListFragment; -import org.thoughtcrime.securesms.R; -import org.thoughtcrime.securesms.contacts.ContactSelectionDisplayMode; -import org.thoughtcrime.securesms.contacts.paged.ChatType; -import org.thoughtcrime.securesms.contacts.selection.ContactSelectionArguments; -import org.thoughtcrime.securesms.contacts.sync.ContactDiscovery; -import org.thoughtcrime.securesms.groups.ui.creategroup.details.AddGroupDetailsActivity; -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.RemoteConfig; -import org.thoughtcrime.securesms.util.views.SimpleProgressDialog; - -import java.io.IOException; -import java.util.List; -import java.util.Optional; -import java.util.Set; -import java.util.concurrent.TimeUnit; -import java.util.function.Consumer; -import java.util.stream.Collectors; - -public class CreateGroupActivity extends ContactSelectionActivity implements ContactSelectionListFragment.FindByCallback { - - private static final String TAG = Log.tag(CreateGroupActivity.class); - - private static final short REQUEST_CODE_ADD_DETAILS = 17275; - - private MaterialButton skip; - private FloatingActionButton next; - private ActivityResultLauncher findByActivityLauncher; - - - public static Intent newIntent(@NonNull Context context) { - Intent intent = new Intent(context, CreateGroupActivity.class); - - intent.putExtra(ContactSelectionArguments.REFRESHABLE, false); - intent.putExtra(ContactSelectionActivity.EXTRA_LAYOUT_RES_ID, R.layout.create_group_activity); - - int displayMode = ContactSelectionDisplayMode.FLAG_PUSH; - - intent.putExtra(ContactSelectionArguments.DISPLAY_MODE, displayMode); - intent.putExtra(ContactSelectionArguments.SELECTION_LIMITS, RemoteConfig.groupLimits().excludingSelf()); - intent.putExtra(ContactSelectionArguments.RV_PADDING_BOTTOM, (int) DimensionUnit.DP.toPixels(64f)); - intent.putExtra(ContactSelectionArguments.RV_CLIP, false); - - return intent; - } - - @Override - public void onCreate(Bundle bundle, boolean ready) { - super.onCreate(bundle, ready); - assert getSupportActionBar() != null; - getSupportActionBar().setDisplayHomeAsUpEnabled(true); - - skip = findViewById(R.id.skip); - next = findViewById(R.id.next); - extendSkip(); - - skip.setOnClickListener(v -> handleNextPressed()); - next.setOnClickListener(v -> handleNextPressed()); - - findByActivityLauncher = registerForActivityResult(new FindByActivity.Contract(), result -> { - if (result != null) { - contactsFragment.addRecipientToSelectionIfAble(result); - } - }); - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - if (item.getItemId() == android.R.id.home) { - finish(); - return true; - } - - return super.onOptionsItemSelected(item); - } - - @Override - protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { - if (requestCode == REQUEST_CODE_ADD_DETAILS && resultCode == RESULT_OK) { - setResult(RESULT_OK); - finish(); - } else { - super.onActivityResult(requestCode, resultCode, data); - } - } - - @Override - public void onBeforeContactSelected(boolean isFromUnknownSearchKey, @NonNull Optional recipientId, String number, @NonNull Optional chatType, @NonNull Consumer callback) { - if (contactsFragment.hasQueryFilter()) { - getContactFilterView().clear(); - } - - shrinkSkip(); - - if (recipientId.isPresent()) { - callback.accept(true); - return; - } - - AlertDialog progress = SimpleProgressDialog.show(this); - - SimpleTask.run(getLifecycle(), () -> RecipientRepository.lookupNewE164(number), result -> { - progress.dismiss(); - - if (result instanceof RecipientRepository.LookupResult.Success) { - callback.accept(true); - } else if (result instanceof RecipientRepository.LookupResult.NotFound || result instanceof RecipientRepository.LookupResult.InvalidEntry) { - new MaterialAlertDialogBuilder(this) - .setMessage(getString(R.string.NewConversationActivity__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, String number, @NonNull Optional chatType) { - if (contactsFragment.hasQueryFilter()) { - getContactFilterView().clear(); - } - - if (contactsFragment.getSelectedContactsCount() == 0) { - extendSkip(); - } - } - - @Override - public void onSelectionChanged() { - int selectedMembers = contactsFragment.getSelectedContactsCount(); - int selectedContactsCount = contactsFragment.getTotalMemberCount(); - if (selectedContactsCount == 0) { - getToolbar().setTitle(getString(R.string.CreateGroupActivity__select_members)); - } else { - getToolbar().setTitle(getResources().getQuantityString(R.plurals.CreateGroupActivity__d_members, selectedMembers, selectedMembers)); - } - } - - @Override - public void onFindByPhoneNumber() { - findByActivityLauncher.launch(FindByMode.PHONE_NUMBER); - } - - @Override - public void onFindByUsername() { - findByActivityLauncher.launch(FindByMode.USERNAME); - } - - private void extendSkip() { - skip.setVisibility(View.VISIBLE); - next.setVisibility(View.GONE); - } - - private void shrinkSkip() { - skip.setVisibility(View.GONE); - next.setVisibility(View.VISIBLE); - } - - private void handleNextPressed() { - Stopwatch stopwatch = new Stopwatch("Recipient Refresh"); - SimpleProgressDialog.DismissibleDialog dismissibleDialog = SimpleProgressDialog.showDelayed(this); - - SimpleTask.run(getLifecycle(), () -> { - List ids = contactsFragment.getSelectedContacts() - .stream() - .map(selectedContact -> selectedContact.getOrCreateRecipientId()) - .collect(Collectors.toList()); - - List resolved = Recipient.resolvedList(ids); - - stopwatch.split("resolve"); - - Set registeredChecks = resolved.stream() - .filter(r -> !r.isRegistered() || !r.getHasServiceId()) - .collect(Collectors.toSet()); - - Log.i(TAG, "Need to do " + registeredChecks.size() + " registration checks."); - - for (Recipient recipient : registeredChecks) { - try { - ContactDiscovery.refresh(this, recipient, false, TimeUnit.SECONDS.toMillis(10)); - } catch (IOException e) { - Log.w(TAG, "Failed to refresh registered status for " + recipient.getId(), e); - } - } - - stopwatch.split("registered"); - - return Recipient.resolvedList(ids); - }, recipients -> { - dismissibleDialog.dismiss(); - stopwatch.stop(TAG); - - List notRegistered = recipients.stream().filter(r -> !r.isRegistered() || !r.getHasServiceId()).collect(Collectors.toList()); - - if (notRegistered.isEmpty()) { - startActivityForResult(AddGroupDetailsActivity.newIntent(this, recipients.stream().map(Recipient::getId).collect(Collectors.toList())), REQUEST_CODE_ADD_DETAILS); - } else { - String notRegisteredNames = notRegistered.stream().map(r -> r.getDisplayName(this)).collect(Collectors.joining(", ")); - new MaterialAlertDialogBuilder(this) - .setMessage(getResources().getQuantityString(R.plurals.CreateGroupActivity_not_signal_users, notRegistered.size(), notRegisteredNames)) - .setPositiveButton(android.R.string.ok, null) - .show(); - } - }); - } -} diff --git a/app/src/main/java/org/thoughtcrime/securesms/groups/ui/creategroup/CreateGroupActivityV2.kt b/app/src/main/java/org/thoughtcrime/securesms/groups/ui/creategroup/CreateGroupActivity.kt similarity index 99% rename from app/src/main/java/org/thoughtcrime/securesms/groups/ui/creategroup/CreateGroupActivityV2.kt rename to app/src/main/java/org/thoughtcrime/securesms/groups/ui/creategroup/CreateGroupActivity.kt index 937cade13d..32f6635d1e 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/groups/ui/creategroup/CreateGroupActivityV2.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/groups/ui/creategroup/CreateGroupActivity.kt @@ -11,8 +11,8 @@ import android.content.Intent import android.os.Bundle import androidx.activity.compose.rememberLauncherForActivityResult import androidx.activity.compose.setContent -import androidx.activity.result.ActivityResult import androidx.activity.enableEdgeToEdge +import androidx.activity.result.ActivityResult import androidx.activity.result.ActivityResultLauncher import androidx.activity.result.contract.ActivityResultContracts import androidx.compose.animation.AnimatedContent @@ -75,11 +75,11 @@ import java.text.NumberFormat /** * Allows creation of a Signal group by selecting from a list of recipients. */ -class CreateGroupActivityV2 : PassphraseRequiredActivity() { +class CreateGroupActivity : PassphraseRequiredActivity() { companion object { @JvmStatic fun createIntent(context: Context): Intent { - return Intent(context, CreateGroupActivityV2::class.java) + return Intent(context, CreateGroupActivity::class.java) } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/megaphone/OnboardingMegaphone.kt b/app/src/main/java/org/thoughtcrime/securesms/megaphone/OnboardingMegaphone.kt index 015719cdca..7b78583a10 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/megaphone/OnboardingMegaphone.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/megaphone/OnboardingMegaphone.kt @@ -312,7 +312,7 @@ abstract class OnboardingState private constructor( override fun onItemActionClick(onboardingListItem: OnboardingListItem) { when (onboardingListItem) { - OnboardingListItem.GROUP -> megaphoneActionController.onMegaphoneNavigationRequested(CreateGroupActivity.newIntent(megaphoneActionController.megaphoneActivity)) + OnboardingListItem.GROUP -> megaphoneActionController.onMegaphoneNavigationRequested(CreateGroupActivity.createIntent(megaphoneActionController.megaphoneActivity)) OnboardingListItem.INVITE -> megaphoneActionController.onMegaphoneNavigationRequested(AppSettingsActivity.invite(megaphoneActionController.megaphoneActivity)) OnboardingListItem.ADD_PHOTO -> { megaphoneActionController.onMegaphoneNavigationRequested(EditProfileActivity.getIntentForAvatarEdit(megaphoneActionController.megaphoneActivity)) diff --git a/app/src/main/res/layout/create_group_activity.xml b/app/src/main/res/layout/create_group_activity.xml deleted file mode 100644 index 8fe8b62ecf..0000000000 --- a/app/src/main/res/layout/create_group_activity.xml +++ /dev/null @@ -1,69 +0,0 @@ - - - - - - - - - - - - - - \ No newline at end of file