diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/InputPanel.java b/app/src/main/java/org/thoughtcrime/securesms/components/InputPanel.java index 696c8bcb7c..9188b3323c 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/InputPanel.java +++ b/app/src/main/java/org/thoughtcrime/securesms/components/InputPanel.java @@ -96,7 +96,6 @@ public class InputPanel extends LinearLayout private boolean hideForGroupState; private boolean hideForBlockedState; private boolean hideForSearch; - private boolean hideForSelection; private ConversationStickerSuggestionAdapter stickerSuggestionAdapter; @@ -337,11 +336,6 @@ public class InputPanel extends LinearLayout updateVisibility(); } - public void setHideForSelection(boolean hideForSelection) { - this.hideForSelection = hideForSelection; - updateVisibility(); - } - @Override public void onRecordPermissionRequired() { if (listener != null) listener.onRecorderPermissionRequired(); @@ -521,7 +515,7 @@ public class InputPanel extends LinearLayout } private void updateVisibility() { - if (hideForGroupState || hideForBlockedState || hideForSearch || hideForSelection) { + if (hideForGroupState || hideForBlockedState || hideForSearch) { setVisibility(GONE); } else { setVisibility(VISIBLE); diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationActivity.java b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationActivity.java index 45af537578..f451b90ee1 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationActivity.java +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationActivity.java @@ -3775,11 +3775,6 @@ public class ConversationActivity extends PassphraseRequiredActivity searchViewItem.collapseActionView(); } - @Override - public void onBottomActionBarVisibilityChanged(int visibility) { - inputPanel.setHideForSelection(visibility == View.VISIBLE); - } - @Override public void onForwardClicked() { inputPanel.clearQuote(); diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationFragment.java b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationFragment.java index 98b991c388..b662a23c96 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationFragment.java +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationFragment.java @@ -25,7 +25,6 @@ import android.app.Activity; import android.content.Context; import android.content.Intent; import android.content.res.Configuration; -import android.graphics.Color; import android.graphics.Rect; import android.net.Uri; import android.os.AsyncTask; @@ -34,6 +33,7 @@ import android.text.SpannableStringBuilder; import android.text.TextUtils; import android.view.LayoutInflater; import android.view.Menu; +import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; @@ -65,19 +65,16 @@ import androidx.recyclerview.widget.RecyclerView.OnScrollListener; import com.annimon.stream.Collectors; import com.annimon.stream.Stream; 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.SignalExecutors; import org.signal.core.util.logging.Log; import org.thoughtcrime.securesms.LoggingFragment; import org.thoughtcrime.securesms.PassphraseRequiredActivity; import org.thoughtcrime.securesms.R; -import org.thoughtcrime.securesms.components.menu.ActionItem; -import org.thoughtcrime.securesms.components.menu.SignalBottomActionBar; import org.thoughtcrime.securesms.verify.VerifyIdentityActivity; import org.thoughtcrime.securesms.components.ConversationScrollToView; import org.thoughtcrime.securesms.components.ConversationTypingView; +import org.thoughtcrime.securesms.components.TooltipPopup; import org.thoughtcrime.securesms.components.TypingStatusRepository; import org.thoughtcrime.securesms.components.recyclerview.SmoothScrollingLinearLayoutManager; import org.thoughtcrime.securesms.components.settings.app.AppSettingsActivity; @@ -165,12 +162,12 @@ import org.thoughtcrime.securesms.util.ViewUtil; import org.thoughtcrime.securesms.util.WindowUtil; import org.thoughtcrime.securesms.util.concurrent.SimpleTask; import org.thoughtcrime.securesms.util.task.ProgressDialogAsyncTask; +import org.thoughtcrime.securesms.util.views.AdaptiveActionsToolbar; import org.thoughtcrime.securesms.wallpaper.ChatWallpaper; import org.whispersystems.libsignal.util.guava.Optional; import java.io.IOException; import java.io.InputStream; -import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; import java.util.List; @@ -227,7 +224,6 @@ public class ConversationFragment extends LoggingFragment implements Multiselect private LayoutTransition layoutTransition; private TransitionListener transitionListener; private View reactionsShade; - private SignalBottomActionBar bottomActionBar; private GiphyMp4ProjectionRecycler giphyMp4ProjectionRecycler; private Colorizer colorizer; @@ -269,7 +265,6 @@ public class ConversationFragment extends LoggingFragment implements Multiselect scrollDateHeader = view.findViewById(R.id.scroll_date_header); toolbarShadow = requireActivity().findViewById(R.id.conversation_toolbar_shadow); reactionsShade = view.findViewById(R.id.reactions_shade); - bottomActionBar = view.findViewById(R.id.conversation_bottom_action_bar); final LinearLayoutManager layoutManager = new SmoothScrollingLinearLayoutManager(getActivity(), true); final ConversationItemAnimator conversationItemAnimator = new ConversationItemAnimator( @@ -288,7 +283,6 @@ public class ConversationFragment extends LoggingFragment implements Multiselect () -> conversationViewModel.getWallpaper().getValue()); list.setHasFixedSize(false); - layoutManager.setStackFromEnd(true); list.setLayoutManager(layoutManager); RecyclerViewColorizer recyclerViewColorizer = new RecyclerViewColorizer(list); @@ -745,7 +739,7 @@ public class ConversationFragment extends LoggingFragment implements Multiselect }); } - private void setCorrectActionModeMenuVisibility() { + private void setCorrectActionModeMenuVisibility(@NonNull Menu menu) { Set selectedParts = getListAdapter().getSelectedItems(); if (actionMode != null && selectedParts.size() == 0) { @@ -753,56 +747,17 @@ public class ConversationFragment extends LoggingFragment implements Multiselect return; } - setBottomActionBarVisibility(true); - MenuState menuState = MenuState.getMenuState(recipient.get(), selectedParts, messageRequestViewModel.shouldShowMessageRequest(), groupViewModel.isNonAdminInAnnouncementGroup()); - List items = new ArrayList<>(); + menu.findItem(R.id.menu_context_forward).setVisible(menuState.shouldShowForwardAction()); + menu.findItem(R.id.menu_context_reply).setVisible(menuState.shouldShowReplyAction()); + menu.findItem(R.id.menu_context_details).setVisible(menuState.shouldShowDetailsAction()); + menu.findItem(R.id.menu_context_save_attachment).setVisible(menuState.shouldShowSaveAttachmentAction()); + menu.findItem(R.id.menu_context_resend).setVisible(menuState.shouldShowResendAction()); + menu.findItem(R.id.menu_context_copy).setVisible(menuState.shouldShowCopyAction()); + menu.findItem(R.id.menu_context_delete_message).setVisible(menuState.shouldShowDeleteAction()); - if (menuState.shouldShowReplyAction()) { - items.add(new ActionItem(R.drawable.ic_reply_24_tinted, getResources().getString(R.string.conversation_context__menu_reply_to_message), () -> { - maybeShowSwipeToReplyTooltip(); - handleReplyMessage(getSelectedConversationMessage()); - actionMode.finish(); - })); - } - - if (menuState.shouldShowForwardAction()) { - items.add(new ActionItem(R.drawable.ic_forward_24_tinted, getResources().getString(R.string.conversation_context__menu_forward_message), () -> handleForwardMessageParts(selectedParts))); - } - - if (menuState.shouldShowSaveAttachmentAction()) { - items.add(new ActionItem(R.drawable.ic_save_24, getResources().getString(R.string.conversation_context_image__save_attachment), () -> { - handleSaveAttachment((MediaMmsMessageRecord) getSelectedConversationMessage().getMessageRecord()); - })); - } - - if (menuState.shouldShowCopyAction()) { - items.add(new ActionItem(R.drawable.ic_copy_24_tinted, getResources().getString(R.string.conversation_context__menu_copy_text), () -> { - handleCopyMessage(selectedParts); - })); - } - - if (menuState.shouldShowDetailsAction()) { - items.add(new ActionItem(R.drawable.ic_info_tinted_24, getResources().getString(R.string.conversation_context__menu_message_details), () -> { - handleDisplayDetails(getSelectedConversationMessage()); - })); - } - - if (menuState.shouldShowDeleteAction()) { - items.add(new ActionItem(R.drawable.ic_delete_tinted_24, getResources().getString(R.string.conversation_context__menu_delete_message), () -> handleDeleteMessages(selectedParts))); - } - - bottomActionBar.setItems(items); - } - - private void setBottomActionBarVisibility(boolean isVisible) { - int visibility = isVisible ? View.VISIBLE : View.GONE; - bottomActionBar.setVisibility(visibility); - listener.onBottomActionBarVisibilityChanged(visibility); - - int bottomPadding = isVisible ? (int) DimensionUnit.DP.toPixels(84) : getResources().getDimensionPixelSize(R.dimen.conversation_bottom_padding); - list.setPadding(list.getPaddingLeft(), list.getPaddingTop(), list.getPaddingRight(), bottomPadding); + AdaptiveActionsToolbar.adjustMenuActions(menu, 10, requireActivity().getWindow().getDecorView().getMeasuredWidth()); } private @Nullable ConversationAdapter getListAdapter() { @@ -814,12 +769,9 @@ public class ConversationFragment extends LoggingFragment implements Multiselect } private ConversationMessage getSelectedConversationMessage() { - Set messageRecords = Stream.of(getListAdapter().getSelectedItems()) - .map(MultiselectPart::getConversationMessage) - .distinct() - .collect(Collectors.toSet()); + Set messageRecords = getListAdapter().getSelectedItems(); - if (messageRecords.size() == 1) return messageRecords.stream().findFirst().get(); + if (messageRecords.size() == 1) return messageRecords.stream().findFirst().get().getConversationMessage(); else throw new AssertionError(); } @@ -1178,9 +1130,11 @@ public class ConversationFragment extends LoggingFragment implements Multiselect if (!TextSecurePreferences.hasSeenSwipeToReplyTooltip(requireContext())) { int text = ViewUtil.isLtr(requireContext()) ? R.string.ConversationFragment_you_can_swipe_to_the_right_reply : R.string.ConversationFragment_you_can_swipe_to_the_left_reply; - Snackbar.make(list, text, Snackbar.LENGTH_LONG) - .setTextColor(Color.WHITE) - .show(); + TooltipPopup.forTarget(requireActivity().findViewById(R.id.menu_context_reply)) + .setText(text) + .setTextColor(getResources().getColor(R.color.core_white)) + .setBackgroundTint(getResources().getColor(R.color.core_ultramarine)) + .show(TooltipPopup.POSITION_BELOW); TextSecurePreferences.setHasSeenSwipeToReplyTooltip(requireContext(), true); } @@ -1250,17 +1204,15 @@ public class ConversationFragment extends LoggingFragment implements Multiselect private @NonNull String calculateSelectedItemCount() { ConversationAdapter adapter = getListAdapter(); - int count = 0; - if (adapter != null && !adapter.getSelectedItems().isEmpty()) { - count = (int) adapter.getSelectedItems() - .stream() - .map(MultiselectPart::getConversationMessage) - .distinct() - .count(); + if (adapter == null || adapter.getSelectedItems().isEmpty()) { + return String.valueOf(0); } - return requireContext().getResources().getQuantityString(R.plurals.conversation_context__s_selected, count, count); - + return String.valueOf(adapter.getSelectedItems() + .stream() + .map(MultiselectPart::getConversationMessage) + .distinct() + .count()); } @Override @@ -1275,7 +1227,6 @@ public class ConversationFragment extends LoggingFragment implements Multiselect void setThreadId(long threadId); void handleReplyMessage(ConversationMessage conversationMessage); void onMessageActionToolbarOpened(); - void onBottomActionBarVisibilityChanged(int visibility); void onForwardClicked(); void onMessageRequest(@NonNull MessageRequestViewModel viewModel); void handleReaction(@NonNull ConversationMessage conversationMessage, @@ -1371,7 +1322,7 @@ public class ConversationFragment extends LoggingFragment implements Multiselect if (getListAdapter().getSelectedItems().size() == 0) { actionMode.finish(); } else { - setCorrectActionModeMenuVisibility(); + setCorrectActionModeMenuVisibility(actionMode.getMenu()); actionMode.setTitle(calculateSelectedItemCount()); } } @@ -1855,9 +1806,12 @@ public class ConversationFragment extends LoggingFragment implements Multiselect @Override public boolean onCreateActionMode(ActionMode mode, Menu menu) { + MenuInflater inflater = mode.getMenuInflater(); + inflater.inflate(R.menu.conversation_context, menu); + mode.setTitle(calculateSelectedItemCount()); - setCorrectActionModeMenuVisibility(); + setCorrectActionModeMenuVisibility(menu); listener.onMessageActionToolbarOpened(); return true; } @@ -1871,12 +1825,44 @@ public class ConversationFragment extends LoggingFragment implements Multiselect public void onDestroyActionMode(ActionMode mode) { ((ConversationAdapter)list.getAdapter()).clearSelection(); list.invalidateItemDecorations(); - setBottomActionBarVisibility(false); actionMode = null; } @Override public boolean onActionItemClicked(ActionMode mode, MenuItem item) { + if (actionMode == null) return false; + + switch(item.getItemId()) { + case R.id.menu_context_copy: + handleCopyMessage(getListAdapter().getSelectedItems()); + actionMode.finish(); + return true; + case R.id.menu_context_delete_message: + handleDeleteMessages(getListAdapter().getSelectedItems()); + actionMode.finish(); + return true; + case R.id.menu_context_details: + handleDisplayDetails(getSelectedConversationMessage()); + actionMode.finish(); + return true; + case R.id.menu_context_forward: + handleForwardMessageParts(getListAdapter().getSelectedItems()); + return true; + case R.id.menu_context_resend: + handleResendMessage(getSelectedConversationMessage().getMessageRecord()); + actionMode.finish(); + return true; + case R.id.menu_context_save_attachment: + handleSaveAttachment((MediaMmsMessageRecord) getSelectedConversationMessage().getMessageRecord()); + actionMode.finish(); + return true; + case R.id.menu_context_reply: + maybeShowSwipeToReplyTooltip(); + handleReplyMessage(getSelectedConversationMessage()); + actionMode.finish(); + return true; + } + return false; } } diff --git a/app/src/main/res/drawable-ldrtl/ic_forward_24_tinted.xml b/app/src/main/res/drawable-ldrtl/ic_forward_24_tinted.xml deleted file mode 100644 index a4074dded0..0000000000 --- a/app/src/main/res/drawable-ldrtl/ic_forward_24_tinted.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - diff --git a/app/src/main/res/drawable-ldrtl/ic_reply_24_tinted.xml b/app/src/main/res/drawable-ldrtl/ic_reply_24_tinted.xml deleted file mode 100644 index 0e77677c20..0000000000 --- a/app/src/main/res/drawable-ldrtl/ic_reply_24_tinted.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - diff --git a/app/src/main/res/drawable-night/ic_delete_tinted_24.xml b/app/src/main/res/drawable-night/ic_delete_tinted_24.xml deleted file mode 100644 index c255646ce7..0000000000 --- a/app/src/main/res/drawable-night/ic_delete_tinted_24.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - diff --git a/app/src/main/res/drawable/ic_delete_tinted_24.xml b/app/src/main/res/drawable/ic_delete_tinted_24.xml deleted file mode 100644 index a87c94dadd..0000000000 --- a/app/src/main/res/drawable/ic_delete_tinted_24.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - diff --git a/app/src/main/res/drawable/ic_forward_24_tinted.xml b/app/src/main/res/drawable/ic_forward_24_tinted.xml deleted file mode 100644 index bf809d6b8d..0000000000 --- a/app/src/main/res/drawable/ic_forward_24_tinted.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - diff --git a/app/src/main/res/drawable/ic_reply_24_tinted.xml b/app/src/main/res/drawable/ic_reply_24_tinted.xml deleted file mode 100644 index 5494c4ce9d..0000000000 --- a/app/src/main/res/drawable/ic_reply_24_tinted.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - diff --git a/app/src/main/res/layout/conversation_activity.xml b/app/src/main/res/layout/conversation_activity.xml index 03e200ead2..5295155fb5 100644 --- a/app/src/main/res/layout/conversation_activity.xml +++ b/app/src/main/res/layout/conversation_activity.xml @@ -49,7 +49,7 @@ android:layout_height="0dp" android:layout_weight="1"> - diff --git a/app/src/main/res/layout/conversation_fragment.xml b/app/src/main/res/layout/conversation_fragment.xml index 8f211ff613..46698a5e30 100644 --- a/app/src/main/res/layout/conversation_fragment.xml +++ b/app/src/main/res/layout/conversation_fragment.xml @@ -22,7 +22,7 @@ android:cacheColorHint="@color/signal_background_primary" android:clipChildren="false" android:clipToPadding="false" - android:paddingBottom="@dimen/conversation_bottom_padding" + android:paddingBottom="2dp" android:scrollbars="vertical" android:overScrollMode="ifContentScrolls" app:layout_constraintTop_toTopOf="parent" /> @@ -88,15 +88,4 @@ app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" /> - - diff --git a/app/src/main/res/menu/conversation_context.xml b/app/src/main/res/menu/conversation_context.xml new file mode 100644 index 0000000000..584cf78b42 --- /dev/null +++ b/app/src/main/res/menu/conversation_context.xml @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml index f94046d31a..dbd5ed969c 100644 --- a/app/src/main/res/values/dimens.xml +++ b/app/src/main/res/values/dimens.xml @@ -69,7 +69,6 @@ 4dp - 2dp 40dp 16dp 16dp diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index db42751a10..ec5a6350b2 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -2785,22 +2785,13 @@ Forward Resend message - - Reply + Reply to message - - + Select multiple - - - %d selected - %d selected - - - - Save + Save attachment Disappearing messages