mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-02-15 07:28:30 +00:00
Enable split pane UI for new conversation screen.
This commit is contained in:
committed by
Cody Henthorne
parent
4fd4792dd8
commit
9d0422a898
@@ -696,13 +696,8 @@
|
||||
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"
|
||||
android:exported="false"/>
|
||||
|
||||
<activity android:name=".NewConversationActivity"
|
||||
android:theme="@style/Theme.Signal.DayNight.NoActionBar"
|
||||
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"
|
||||
android:exported="false"/>
|
||||
|
||||
<activity
|
||||
android:name=".conversation.NewConversationActivityV2"
|
||||
android:name=".conversation.NewConversationActivity"
|
||||
android:exported="false"
|
||||
android:theme="@style/Signal.DayNight.NoActionBar" />
|
||||
|
||||
|
||||
@@ -92,6 +92,7 @@ import org.thoughtcrime.securesms.components.settings.app.notifications.manual.N
|
||||
import org.thoughtcrime.securesms.components.voice.VoiceNoteMediaController
|
||||
import org.thoughtcrime.securesms.components.voice.VoiceNoteMediaControllerOwner
|
||||
import org.thoughtcrime.securesms.conversation.ConversationIntents
|
||||
import org.thoughtcrime.securesms.conversation.NewConversationActivity
|
||||
import org.thoughtcrime.securesms.conversation.v2.MotionEventRelay
|
||||
import org.thoughtcrime.securesms.conversation.v2.ShareDataTimestampViewModel
|
||||
import org.thoughtcrime.securesms.conversationlist.ConversationListArchiveFragment
|
||||
@@ -1005,7 +1006,7 @@ class MainActivity : PassphraseRequiredActivity(), VoiceNoteMediaControllerOwner
|
||||
|
||||
inner class BottomChromeCallback : MainBottomChromeCallback {
|
||||
override fun onNewChatClick() {
|
||||
startActivity(Intent(this@MainActivity, NewConversationActivity::class.java))
|
||||
startActivity(NewConversationActivity.createIntent(this@MainActivity))
|
||||
}
|
||||
|
||||
override fun onNewCallClick() {
|
||||
|
||||
@@ -1,403 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Open Whisper Systems
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.thoughtcrime.securesms;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.activity.result.ActivityResultLauncher;
|
||||
import androidx.activity.result.contract.ActivityResultContracts;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.StringRes;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.lifecycle.ViewModelProvider;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||
import com.google.android.material.snackbar.Snackbar;
|
||||
|
||||
import org.signal.core.util.DimensionUnit;
|
||||
import org.signal.core.util.concurrent.LifecycleDisposable;
|
||||
import org.signal.core.util.concurrent.SimpleTask;
|
||||
import org.signal.core.util.logging.Log;
|
||||
import org.thoughtcrime.securesms.calls.YouAreAlreadyInACallSnackbar;
|
||||
import org.thoughtcrime.securesms.components.menu.ActionItem;
|
||||
import org.thoughtcrime.securesms.components.menu.SignalContextMenu;
|
||||
import org.thoughtcrime.securesms.components.settings.app.AppSettingsActivity;
|
||||
import org.thoughtcrime.securesms.contacts.management.ContactsManagementRepository;
|
||||
import org.thoughtcrime.securesms.contacts.management.ContactsManagementViewModel;
|
||||
import org.thoughtcrime.securesms.contacts.paged.ChatType;
|
||||
import org.thoughtcrime.securesms.contacts.paged.ContactSearchKey;
|
||||
import org.thoughtcrime.securesms.conversation.ConversationIntents;
|
||||
import org.thoughtcrime.securesms.groups.ui.creategroup.CreateGroupActivity;
|
||||
import org.thoughtcrime.securesms.keyvalue.SignalStore;
|
||||
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.CommunicationActions;
|
||||
import org.thoughtcrime.securesms.util.views.SimpleProgressDialog;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import io.reactivex.rxjava3.disposables.Disposable;
|
||||
|
||||
/**
|
||||
* Activity container for starting a new conversation.
|
||||
*
|
||||
* @author Moxie Marlinspike
|
||||
*/
|
||||
public class NewConversationActivity extends ContactSelectionActivity
|
||||
implements ContactSelectionListFragment.NewConversationCallback, ContactSelectionListFragment.OnItemLongClickListener, ContactSelectionListFragment.FindByCallback
|
||||
{
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private static final String TAG = Log.tag(NewConversationActivity.class);
|
||||
|
||||
private ContactsManagementViewModel viewModel;
|
||||
private ActivityResultLauncher<Intent> contactLauncher;
|
||||
private ActivityResultLauncher<Intent> createGroupLauncher;
|
||||
private ActivityResultLauncher<FindByMode> findByLauncher;
|
||||
|
||||
private final LifecycleDisposable disposables = new LifecycleDisposable();
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle bundle, boolean ready) {
|
||||
super.onCreate(bundle, ready);
|
||||
assert getSupportActionBar() != null;
|
||||
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
||||
getSupportActionBar().setTitle(R.string.NewConversationActivity__new_message);
|
||||
|
||||
disposables.bindTo(this);
|
||||
|
||||
ContactsManagementRepository repository = new ContactsManagementRepository(this);
|
||||
ContactsManagementViewModel.Factory factory = new ContactsManagementViewModel.Factory(repository);
|
||||
|
||||
contactLauncher = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), activityResult -> {
|
||||
if (activityResult.getResultCode() != RESULT_CANCELED) {
|
||||
handleManualRefresh();
|
||||
}
|
||||
});
|
||||
|
||||
findByLauncher = registerForActivityResult(new FindByActivity.Contract(), result -> {
|
||||
if (result != null) {
|
||||
launch(result);
|
||||
}
|
||||
});
|
||||
|
||||
createGroupLauncher = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), result -> {
|
||||
if (result.getResultCode() == RESULT_OK) {
|
||||
finish();
|
||||
}
|
||||
});
|
||||
|
||||
viewModel = new ViewModelProvider(this, factory).get(ContactsManagementViewModel.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBeforeContactSelected(boolean isFromUnknownSearchKey, @NonNull Optional<RecipientId> recipientId, String number, @NonNull Optional<ChatType> chatType, @NonNull Consumer<Boolean> callback) {
|
||||
if (recipientId.isPresent()) {
|
||||
launch(Recipient.resolved(recipientId.get()));
|
||||
} else {
|
||||
Log.i(TAG, "[onContactSelected] Maybe creating a new recipient.");
|
||||
|
||||
if (SignalStore.account().isRegistered()) {
|
||||
Log.i(TAG, "[onContactSelected] Doing contact refresh.");
|
||||
|
||||
AlertDialog progress = SimpleProgressDialog.show(this);
|
||||
|
||||
SimpleTask.run(getLifecycle(), () -> RecipientRepository.lookupNewE164(number), result -> {
|
||||
progress.dismiss();
|
||||
|
||||
if (result instanceof RecipientRepository.LookupResult.Success) {
|
||||
Recipient resolved = Recipient.resolved(((RecipientRepository.LookupResult.Success) result).getRecipientId());
|
||||
if (resolved.isRegistered() && resolved.getHasServiceId()) {
|
||||
launch(resolved);
|
||||
}
|
||||
} 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();
|
||||
} 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(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSelectionChanged() {
|
||||
}
|
||||
|
||||
private void launch(Recipient recipient) {
|
||||
launch(recipient.getId());
|
||||
}
|
||||
|
||||
|
||||
private void launch(RecipientId recipientId) {
|
||||
Disposable disposable = ConversationIntents.createBuilder(this, recipientId, -1L)
|
||||
.map(builder -> builder
|
||||
.withDraftText(getIntent().getStringExtra(Intent.EXTRA_TEXT))
|
||||
.withDataUri(getIntent().getData())
|
||||
.withDataType(getIntent().getType())
|
||||
.build())
|
||||
.subscribe(intent -> {
|
||||
startActivity(intent);
|
||||
finish();
|
||||
});
|
||||
|
||||
disposables.add(disposable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
super.onOptionsItemSelected(item);
|
||||
|
||||
int itemId = item.getItemId();
|
||||
|
||||
if (itemId == android.R.id.home) {
|
||||
super.onBackPressed();
|
||||
return true;
|
||||
} else if (itemId == R.id.menu_refresh) {
|
||||
handleManualRefresh();
|
||||
return true;
|
||||
} else if (itemId == R.id.menu_new_group) {
|
||||
handleCreateGroup();
|
||||
return true;
|
||||
} else if (itemId == R.id.menu_invite) {
|
||||
handleInvite();
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private void handleManualRefresh() {
|
||||
if (!contactsFragment.isRefreshing()) {
|
||||
contactsFragment.setRefreshing(true);
|
||||
onRefresh();
|
||||
}
|
||||
}
|
||||
|
||||
private void handleCreateGroup() {
|
||||
createGroupLauncher.launch(CreateGroupActivity.newIntent(this));
|
||||
}
|
||||
|
||||
private void handleInvite() {
|
||||
startActivity(AppSettingsActivity.invite(this));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
menu.clear();
|
||||
getMenuInflater().inflate(R.menu.new_conversation_activity, menu);
|
||||
|
||||
super.onCreateOptionsMenu(menu);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onInvite() {
|
||||
handleInvite();
|
||||
finish();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNewGroup(boolean forceV1) {
|
||||
handleCreateGroup();
|
||||
// finish();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFindByUsername() {
|
||||
findByLauncher.launch(FindByMode.USERNAME);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFindByPhoneNumber() {
|
||||
findByLauncher.launch(FindByMode.PHONE_NUMBER);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onLongClick(View anchorView, ContactSearchKey contactSearchKey, RecyclerView recyclerView) {
|
||||
RecipientId recipientId = contactSearchKey.requireRecipientSearchKey().getRecipientId();
|
||||
List<ActionItem> actions = generateContextualActionsForRecipient(recipientId);
|
||||
if (actions.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
new SignalContextMenu.Builder(anchorView, (ViewGroup) anchorView.getRootView())
|
||||
.preferredVerticalPosition(SignalContextMenu.VerticalPosition.BELOW)
|
||||
.preferredHorizontalPosition(SignalContextMenu.HorizontalPosition.START)
|
||||
.offsetX((int) DimensionUnit.DP.toPixels(12))
|
||||
.offsetY((int) DimensionUnit.DP.toPixels(12))
|
||||
.onDismiss(() -> recyclerView.suppressLayout(false))
|
||||
.show(actions);
|
||||
|
||||
recyclerView.suppressLayout(true);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private @NonNull List<ActionItem> generateContextualActionsForRecipient(@NonNull RecipientId recipientId) {
|
||||
Recipient recipient = Recipient.resolved(recipientId);
|
||||
|
||||
return Stream.of(
|
||||
createMessageActionItem(recipient),
|
||||
createAudioCallActionItem(recipient),
|
||||
createVideoCallActionItem(recipient),
|
||||
createRemoveActionItem(recipient),
|
||||
createBlockActionItem(recipient)
|
||||
).filter(Objects::nonNull).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private @NonNull ActionItem createMessageActionItem(@NonNull Recipient recipient) {
|
||||
return new ActionItem(
|
||||
R.drawable.ic_chat_message_24,
|
||||
getString(R.string.NewConversationActivity__message),
|
||||
R.color.signal_colorOnSurface,
|
||||
() -> {
|
||||
Disposable disposable = ConversationIntents.createBuilder(this, recipient.getId(), -1L)
|
||||
.subscribe(builder -> startActivity(builder.build()));
|
||||
|
||||
disposables.add(disposable);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
private @Nullable ActionItem createAudioCallActionItem(@NonNull Recipient recipient) {
|
||||
if (recipient.isSelf() || recipient.isGroup()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (recipient.isRegistered()) {
|
||||
return new ActionItem(
|
||||
R.drawable.ic_phone_right_24,
|
||||
getString(R.string.NewConversationActivity__audio_call),
|
||||
R.color.signal_colorOnSurface,
|
||||
() -> CommunicationActions.startVoiceCall(this, recipient, () -> {
|
||||
YouAreAlreadyInACallSnackbar.show(findViewById(android.R.id.content));
|
||||
})
|
||||
);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private @Nullable ActionItem createVideoCallActionItem(@NonNull Recipient recipient) {
|
||||
if (recipient.isSelf() || recipient.isMmsGroup() || !recipient.isRegistered()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new ActionItem(
|
||||
R.drawable.ic_video_call_24,
|
||||
getString(R.string.NewConversationActivity__video_call),
|
||||
R.color.signal_colorOnSurface,
|
||||
() -> CommunicationActions.startVideoCall(this, recipient, () -> {
|
||||
YouAreAlreadyInACallSnackbar.show(findViewById(android.R.id.content));
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
private @Nullable ActionItem createRemoveActionItem(@NonNull Recipient recipient) {
|
||||
if (recipient.isSelf() || recipient.isGroup()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new ActionItem(
|
||||
R.drawable.ic_minus_circle_20, // TODO [alex] -- correct asset
|
||||
getString(R.string.NewConversationActivity__remove),
|
||||
R.color.signal_colorOnSurface,
|
||||
() -> displayRemovalDialog(recipient)
|
||||
);
|
||||
}
|
||||
|
||||
@SuppressWarnings("CodeBlock2Expr")
|
||||
private @Nullable ActionItem createBlockActionItem(@NonNull Recipient recipient) {
|
||||
if (recipient.isSelf()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new ActionItem(
|
||||
R.drawable.ic_block_tinted_24,
|
||||
getString(R.string.NewConversationActivity__block),
|
||||
R.color.signal_colorError,
|
||||
() -> BlockUnblockDialog.showBlockFor(this,
|
||||
this.getLifecycle(),
|
||||
recipient,
|
||||
() -> {
|
||||
disposables.add(viewModel.blockContact(recipient).subscribe(() -> {
|
||||
handleManualRefresh();
|
||||
displaySnackbar(R.string.NewConversationActivity__s_has_been_blocked, recipient.getDisplayName(this));
|
||||
contactsFragment.reset();
|
||||
}, (throwable) -> {
|
||||
displaySnackbar(R.string.NewConversationActivity__block_failed);
|
||||
}));
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
private void displayIsInSystemContactsDialog(@NonNull Recipient recipient) {
|
||||
new MaterialAlertDialogBuilder(this)
|
||||
.setTitle(getString(R.string.NewConversationActivity__unable_to_remove_s, recipient.getShortDisplayName(this)))
|
||||
.setMessage(R.string.NewConversationActivity__this_person_is_saved_to_your)
|
||||
.setPositiveButton(R.string.NewConversationActivity__view_contact,
|
||||
(dialog, which) -> contactLauncher.launch(new Intent(Intent.ACTION_VIEW, recipient.getContactUri()))
|
||||
)
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.show();
|
||||
}
|
||||
|
||||
private void displayRemovalDialog(@NonNull Recipient recipient) {
|
||||
new MaterialAlertDialogBuilder(this)
|
||||
.setTitle(getString(R.string.NewConversationActivity__remove_s, recipient.getShortDisplayName(this)))
|
||||
.setMessage(R.string.NewConversationActivity__you_wont_see_this_person)
|
||||
.setPositiveButton(R.string.NewConversationActivity__remove,
|
||||
(dialog, which) -> {
|
||||
disposables.add(viewModel.hideContact(recipient).subscribe(() -> {
|
||||
handleManualRefresh();
|
||||
displaySnackbar(R.string.NewConversationActivity__s_has_been_removed, recipient.getDisplayName(this));
|
||||
contactsFragment.reset();
|
||||
}));
|
||||
}
|
||||
)
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.show();
|
||||
}
|
||||
|
||||
private void displaySnackbar(@StringRes int message, Object... formatArgs) {
|
||||
Snackbar.make(findViewById(android.R.id.content), getString(message, formatArgs), Snackbar.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
@@ -12,6 +12,7 @@ import androidx.annotation.NonNull;
|
||||
|
||||
import org.signal.core.util.logging.Log;
|
||||
import org.thoughtcrime.securesms.conversation.ConversationIntents;
|
||||
import org.thoughtcrime.securesms.conversation.NewConversationActivity;
|
||||
import org.thoughtcrime.securesms.database.SignalDatabase;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.util.Rfc5724Uri;
|
||||
@@ -41,8 +42,7 @@ public class SystemContactsEntrypointActivity extends Activity {
|
||||
final Intent nextIntent;
|
||||
|
||||
if (TextUtils.isEmpty(destination.destination)) {
|
||||
nextIntent = new Intent(this, NewConversationActivity.class);
|
||||
nextIntent.putExtra(Intent.EXTRA_TEXT, destination.getBody());
|
||||
nextIntent = NewConversationActivity.createIntent(this, destination.getBody());
|
||||
Toast.makeText(this, R.string.ConversationActivity_specify_recipient, Toast.LENGTH_LONG).show();
|
||||
} else {
|
||||
Recipient recipient = Recipient.external(destination.getDestination());
|
||||
@@ -54,8 +54,7 @@ public class SystemContactsEntrypointActivity extends Activity {
|
||||
.withDraftText(destination.getBody())
|
||||
.build();
|
||||
} else {
|
||||
nextIntent = new Intent(this, NewConversationActivity.class);
|
||||
nextIntent.putExtra(Intent.EXTRA_TEXT, destination.getBody());
|
||||
nextIntent = NewConversationActivity.createIntent(this, destination.getBody());
|
||||
Toast.makeText(this, R.string.ConversationActivity_specify_recipient, Toast.LENGTH_LONG).show();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
package org.thoughtcrime.securesms.contacts.management
|
||||
|
||||
import androidx.annotation.CheckResult
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.rxjava3.core.Completable
|
||||
import org.thoughtcrime.securesms.recipients.Recipient
|
||||
|
||||
class ContactsManagementViewModel(private val repository: ContactsManagementRepository) : ViewModel() {
|
||||
|
||||
@CheckResult
|
||||
fun hideContact(recipient: Recipient): Completable {
|
||||
return repository.hideContact(recipient).observeOn(AndroidSchedulers.mainThread())
|
||||
}
|
||||
|
||||
@CheckResult
|
||||
fun blockContact(recipient: Recipient): Completable {
|
||||
return repository.blockContact(recipient).observeOn(AndroidSchedulers.mainThread())
|
||||
}
|
||||
|
||||
class Factory(private val repository: ContactsManagementRepository) : ViewModelProvider.Factory {
|
||||
override fun <T : ViewModel> create(modelClass: Class<T>): T {
|
||||
return modelClass.cast(ContactsManagementViewModel(repository)) as T
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -68,13 +68,16 @@ import org.thoughtcrime.securesms.window.rememberAppScaffoldNavigator
|
||||
|
||||
/**
|
||||
* Allows the user to start a new conversation by selecting a recipient.
|
||||
*
|
||||
* A modernized compose-based replacement for [org.thoughtcrime.securesms.NewConversationActivity].
|
||||
*/
|
||||
class NewConversationActivityV2 : PassphraseRequiredActivity() {
|
||||
class NewConversationActivity : PassphraseRequiredActivity() {
|
||||
companion object {
|
||||
@JvmOverloads
|
||||
@JvmStatic
|
||||
fun createIntent(context: Context): Intent = Intent(context, NewConversationActivityV2::class.java)
|
||||
fun createIntent(context: Context, draftMessage: String? = null): Intent {
|
||||
return Intent(context, NewConversationActivity::class.java).apply {
|
||||
putExtra(Intent.EXTRA_TEXT, draftMessage)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?, ready: Boolean) {
|
||||
@@ -121,7 +124,7 @@ private fun NewConversationScreen(
|
||||
|
||||
val coroutineScope = rememberCoroutineScope()
|
||||
val callbacks = remember {
|
||||
object : Callbacks {
|
||||
object : UiCallbacks {
|
||||
override fun onCreateNewGroup() = createGroupLauncher.launch(CreateGroupActivity.newIntent(context))
|
||||
override fun onFindByUsername() = findByLauncher.launch(FindByMode.USERNAME)
|
||||
override fun onFindByPhoneNumber() = findByLauncher.launch(FindByMode.PHONE_NUMBER)
|
||||
@@ -191,7 +194,7 @@ private suspend fun openConversation(
|
||||
@Composable
|
||||
private fun NewConversationScreenUi(
|
||||
uiState: NewConversationUiState,
|
||||
callbacks: Callbacks
|
||||
callbacks: UiCallbacks
|
||||
) {
|
||||
val windowSizeClass = WindowSizeClass.rememberWindowSizeClass()
|
||||
val isSplitPane = windowSizeClass.isSplitPane(forceSplitPaneOnCompactLandscape = uiState.forceSplitPaneOnCompactLandscape)
|
||||
@@ -259,7 +262,7 @@ private fun NewConversationScreenUi(
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun TopAppBarActions(callbacks: Callbacks) {
|
||||
private fun TopAppBarActions(callbacks: UiCallbacks) {
|
||||
val menuController = remember { DropdownMenus.MenuController() }
|
||||
IconButton(
|
||||
onClick = { menuController.show() },
|
||||
@@ -303,13 +306,13 @@ private fun TopAppBarActions(callbacks: Callbacks) {
|
||||
}
|
||||
}
|
||||
|
||||
private interface Callbacks : RecipientPickerCallbacks {
|
||||
private interface UiCallbacks : RecipientPickerCallbacks {
|
||||
fun onRemoveConfirmed(recipient: Recipient)
|
||||
fun onBlockConfirmed(recipient: Recipient)
|
||||
fun onUserMessageDismissed(userMessage: UserMessage)
|
||||
fun onBackPressed()
|
||||
|
||||
object Empty : Callbacks {
|
||||
object Empty : UiCallbacks {
|
||||
override fun onCreateNewGroup() = Unit
|
||||
override fun onFindByUsername() = Unit
|
||||
override fun onFindByPhoneNumber() = Unit
|
||||
@@ -333,7 +336,7 @@ private interface Callbacks : RecipientPickerCallbacks {
|
||||
@Composable
|
||||
private fun NewConversationRecipientPicker(
|
||||
uiState: NewConversationUiState,
|
||||
callbacks: Callbacks,
|
||||
callbacks: UiCallbacks,
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
RecipientPicker(
|
||||
@@ -423,7 +426,7 @@ private fun NewConversationScreenPreview() {
|
||||
uiState = NewConversationUiState(
|
||||
forceSplitPaneOnCompactLandscape = false
|
||||
),
|
||||
callbacks = Callbacks.Empty
|
||||
callbacks = UiCallbacks.Empty
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -113,7 +113,7 @@ private fun RecipientSearchField(
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(jeff) This causes the keyboard to re-open on rotation, which doesn't match the existing behavior of ContactFilterView. To fix this,
|
||||
// TODO [jeff] This causes the keyboard to re-open on rotation, which doesn't match the existing behavior of ContactFilterView. To fix this,
|
||||
// RecipientSearchField needs to be converted to compose so we can use FocusRequestor.
|
||||
LaunchedEffect(focusAndShowKeyboard) {
|
||||
if (focusAndShowKeyboard) {
|
||||
@@ -298,7 +298,7 @@ private suspend fun showItemContextMenu(anchorView: View, contactSearchKey: Cont
|
||||
|
||||
if (!recipient.isSelf && !recipient.isGroup) {
|
||||
val removeItem = ActionItem(
|
||||
iconRes = R.drawable.ic_minus_circle_20, // TODO [alex] -- correct asset
|
||||
iconRes = R.drawable.ic_minus_circle_20,
|
||||
title = context.getString(R.string.NewConversationActivity__remove),
|
||||
tintRes = R.color.signal_colorOnSurface,
|
||||
action = { callbacks.onRemove(recipient) }
|
||||
|
||||
@@ -15,8 +15,8 @@ import androidx.core.content.ContextCompat;
|
||||
|
||||
import org.signal.core.util.SetUtil;
|
||||
import org.signal.core.util.logging.Log;
|
||||
import org.thoughtcrime.securesms.NewConversationActivity;
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.conversation.NewConversationActivity;
|
||||
import org.thoughtcrime.securesms.conversationlist.model.ConversationFilter;
|
||||
import org.thoughtcrime.securesms.database.SignalDatabase;
|
||||
import org.thoughtcrime.securesms.database.ThreadTable;
|
||||
@@ -108,7 +108,7 @@ public class UserNotificationMigrationJob extends MigrationJob {
|
||||
registeredSystemContacts.size());
|
||||
|
||||
Intent mainActivityIntent = new Intent(context, MainActivity.class);
|
||||
Intent newConversationIntent = new Intent(context, NewConversationActivity.class);
|
||||
Intent newConversationIntent = NewConversationActivity.createIntent(context);
|
||||
PendingIntent pendingIntent = TaskStackBuilder.create(context)
|
||||
.addNextIntent(mainActivityIntent)
|
||||
.addNextIntent(newConversationIntent)
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<item android:title="@string/new_conversation_activity__refresh"
|
||||
android:id="@+id/menu_refresh"
|
||||
app:showAsAction="never" />
|
||||
|
||||
<item android:title="@string/text_secure_normal__menu_new_group"
|
||||
android:id="@+id/menu_new_group" />
|
||||
|
||||
<item android:title="@string/text_secure_normal__invite_friends"
|
||||
android:id="@+id/menu_invite" />
|
||||
|
||||
</menu>
|
||||
@@ -5910,12 +5910,6 @@
|
||||
<string name="NewConversationActivity__s_has_been_blocked">%1$s has been blocked</string>
|
||||
<!-- Snackbar message when blocking a contact has failed -->
|
||||
<string name="NewConversationActivity__block_failed">Block failed</string>
|
||||
<!-- Dialog title when remove target contact is in system contacts -->
|
||||
<string name="NewConversationActivity__unable_to_remove_s">Unable to remove %1$s</string>
|
||||
<!-- Dialog message when remove target contact is in system contacts -->
|
||||
<string name="NewConversationActivity__this_person_is_saved_to_your">This person is saved to your device\'s Contacts. Delete them from your Contacts and try again.</string>
|
||||
<!-- Dialog action to view contact when they can\'t be removed otherwise -->
|
||||
<string name="NewConversationActivity__view_contact">View contact</string>
|
||||
<!-- Error message shown when looking up a person by phone number and that phone number is not associated with a signal account -->
|
||||
<string name="NewConversationActivity__s_is_not_a_signal_user">%1$s is not a Signal user</string>
|
||||
<!-- Accessibility label for opening the screen specific dropdown menu. -->
|
||||
|
||||
Reference in New Issue
Block a user