Implement bottom selection menu in chat.
This commit is contained in:
parent
917744f091
commit
3943e670b2
15 changed files with 209 additions and 122 deletions
|
@ -96,6 +96,7 @@ public class InputPanel extends LinearLayout
|
|||
private boolean hideForGroupState;
|
||||
private boolean hideForBlockedState;
|
||||
private boolean hideForSearch;
|
||||
private boolean hideForSelection;
|
||||
|
||||
private ConversationStickerSuggestionAdapter stickerSuggestionAdapter;
|
||||
|
||||
|
@ -336,6 +337,11 @@ public class InputPanel extends LinearLayout
|
|||
updateVisibility();
|
||||
}
|
||||
|
||||
public void setHideForSelection(boolean hideForSelection) {
|
||||
this.hideForSelection = hideForSelection;
|
||||
updateVisibility();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRecordPermissionRequired() {
|
||||
if (listener != null) listener.onRecorderPermissionRequired();
|
||||
|
@ -515,7 +521,7 @@ public class InputPanel extends LinearLayout
|
|||
}
|
||||
|
||||
private void updateVisibility() {
|
||||
if (hideForGroupState || hideForBlockedState || hideForSearch) {
|
||||
if (hideForGroupState || hideForBlockedState || hideForSearch || hideForSelection) {
|
||||
setVisibility(GONE);
|
||||
} else {
|
||||
setVisibility(VISIBLE);
|
||||
|
|
|
@ -3775,6 +3775,11 @@ public class ConversationActivity extends PassphraseRequiredActivity
|
|||
searchViewItem.collapseActionView();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBottomActionBarVisibilityChanged(int visibility) {
|
||||
inputPanel.setHideForSelection(visibility == View.VISIBLE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onForwardClicked() {
|
||||
inputPanel.clearQuote();
|
||||
|
|
|
@ -25,6 +25,7 @@ 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;
|
||||
|
@ -33,7 +34,6 @@ 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;
|
||||
|
@ -55,6 +55,7 @@ import androidx.core.app.ActivityCompat;
|
|||
import androidx.core.app.ActivityOptionsCompat;
|
||||
import androidx.core.text.HtmlCompat;
|
||||
import androidx.core.view.ViewCompat;
|
||||
import androidx.core.view.ViewKt;
|
||||
import androidx.lifecycle.LiveData;
|
||||
import androidx.lifecycle.Observer;
|
||||
import androidx.lifecycle.ViewModelProviders;
|
||||
|
@ -65,17 +66,19 @@ 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.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.menu.ActionItem;
|
||||
import org.thoughtcrime.securesms.components.menu.SignalBottomActionBar;
|
||||
import org.thoughtcrime.securesms.components.recyclerview.SmoothScrollingLinearLayoutManager;
|
||||
import org.thoughtcrime.securesms.components.settings.app.AppSettingsActivity;
|
||||
import org.thoughtcrime.securesms.components.voice.VoiceNoteMediaControllerOwner;
|
||||
|
@ -160,20 +163,23 @@ import org.thoughtcrime.securesms.util.TopToastPopup;
|
|||
import org.thoughtcrime.securesms.util.Util;
|
||||
import org.thoughtcrime.securesms.util.ViewUtil;
|
||||
import org.thoughtcrime.securesms.util.WindowUtil;
|
||||
import org.thoughtcrime.securesms.util.concurrent.ListenableFuture;
|
||||
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.verify.VerifyIdentityActivity;
|
||||
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;
|
||||
import java.util.Locale;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
import kotlin.Unit;
|
||||
|
||||
|
@ -224,6 +230,7 @@ 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;
|
||||
|
@ -265,6 +272,7 @@ 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(
|
||||
|
@ -739,7 +747,7 @@ public class ConversationFragment extends LoggingFragment implements Multiselect
|
|||
});
|
||||
}
|
||||
|
||||
private void setCorrectActionModeMenuVisibility(@NonNull Menu menu) {
|
||||
private void setCorrectActionModeMenuVisibility() {
|
||||
Set<MultiselectPart> selectedParts = getListAdapter().getSelectedItems();
|
||||
|
||||
if (actionMode != null && selectedParts.size() == 0) {
|
||||
|
@ -747,17 +755,86 @@ public class ConversationFragment extends LoggingFragment implements Multiselect
|
|||
return;
|
||||
}
|
||||
|
||||
setBottomActionBarVisibility(true);
|
||||
|
||||
MenuState menuState = MenuState.getMenuState(recipient.get(), selectedParts, messageRequestViewModel.shouldShowMessageRequest(), groupViewModel.isNonAdminInAnnouncementGroup());
|
||||
|
||||
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());
|
||||
List<ActionItem> items = new ArrayList<>();
|
||||
|
||||
AdaptiveActionsToolbar.adjustMenuActions(menu, 10, requireActivity().getWindow().getDecorView().getMeasuredWidth());
|
||||
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());
|
||||
actionMode.finish();
|
||||
}));
|
||||
}
|
||||
|
||||
if (menuState.shouldShowCopyAction()) {
|
||||
items.add(new ActionItem(R.drawable.ic_copy_24_tinted, getResources().getString(R.string.conversation_context__menu_copy_text), () -> {
|
||||
handleCopyMessage(selectedParts);
|
||||
actionMode.finish();
|
||||
}));
|
||||
}
|
||||
|
||||
if (menuState.shouldShowDetailsAction()) {
|
||||
items.add(new ActionItem(R.drawable.ic_info_tinted_24, getResources().getString(R.string.conversation_context__menu_message_details), () -> {
|
||||
handleDisplayDetails(getSelectedConversationMessage());
|
||||
actionMode.finish();
|
||||
}));
|
||||
}
|
||||
|
||||
if (menuState.shouldShowDeleteAction()) {
|
||||
items.add(new ActionItem(R.drawable.ic_delete_tinted_24, getResources().getString(R.string.conversation_context__menu_delete_message), () -> {
|
||||
handleDeleteMessages(selectedParts);
|
||||
actionMode.finish();
|
||||
}));
|
||||
}
|
||||
|
||||
bottomActionBar.setItems(items);
|
||||
}
|
||||
|
||||
private void setBottomActionBarVisibility(boolean isVisible) {
|
||||
boolean isCurrentlyVisible = bottomActionBar.getVisibility() == View.VISIBLE;
|
||||
if (isVisible == isCurrentlyVisible) {
|
||||
return;
|
||||
}
|
||||
|
||||
int scrollOffset = (int) DimensionUnit.DP.toPixels(34);
|
||||
|
||||
if (isVisible) {
|
||||
ViewUtil.animateIn(bottomActionBar, bottomActionBar.getEnterAnimation());
|
||||
listener.onBottomActionBarVisibilityChanged(View.VISIBLE);
|
||||
|
||||
list.setPadding(list.getPaddingLeft(), list.getPaddingTop(), list.getPaddingRight(), (int) DimensionUnit.DP.toPixels(88));
|
||||
list.scrollBy(0, -scrollOffset);
|
||||
} else {
|
||||
ViewUtil.animateOut(bottomActionBar, bottomActionBar.getExitAnimation())
|
||||
.addListener(new ListenableFuture.Listener<Boolean>() {
|
||||
@Override public void onSuccess(Boolean result) {
|
||||
listener.onBottomActionBarVisibilityChanged(View.GONE);
|
||||
list.setPadding(list.getPaddingLeft(), list.getPaddingTop(), list.getPaddingRight(), getResources().getDimensionPixelSize(R.dimen.conversation_bottom_padding));
|
||||
|
||||
ViewKt.doOnPreDraw(list, view -> {
|
||||
list.scrollBy(0, scrollOffset);
|
||||
return Unit.INSTANCE;
|
||||
});
|
||||
}
|
||||
|
||||
@Override public void onFailure(ExecutionException e) {
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private @Nullable ConversationAdapter getListAdapter() {
|
||||
|
@ -769,9 +846,12 @@ public class ConversationFragment extends LoggingFragment implements Multiselect
|
|||
}
|
||||
|
||||
private ConversationMessage getSelectedConversationMessage() {
|
||||
Set<MultiselectPart> messageRecords = getListAdapter().getSelectedItems();
|
||||
Set<ConversationMessage> messageRecords = Stream.of(getListAdapter().getSelectedItems())
|
||||
.map(MultiselectPart::getConversationMessage)
|
||||
.distinct()
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
if (messageRecords.size() == 1) return messageRecords.stream().findFirst().get().getConversationMessage();
|
||||
if (messageRecords.size() == 1) return messageRecords.stream().findFirst().get();
|
||||
else throw new AssertionError();
|
||||
}
|
||||
|
||||
|
@ -1130,11 +1210,9 @@ 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;
|
||||
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);
|
||||
Snackbar.make(list, text, Snackbar.LENGTH_LONG)
|
||||
.setTextColor(Color.WHITE)
|
||||
.show();
|
||||
|
||||
TextSecurePreferences.setHasSeenSwipeToReplyTooltip(requireContext(), true);
|
||||
}
|
||||
|
@ -1204,15 +1282,17 @@ public class ConversationFragment extends LoggingFragment implements Multiselect
|
|||
|
||||
private @NonNull String calculateSelectedItemCount() {
|
||||
ConversationAdapter adapter = getListAdapter();
|
||||
if (adapter == null || adapter.getSelectedItems().isEmpty()) {
|
||||
return String.valueOf(0);
|
||||
int count = 0;
|
||||
if (adapter != null && !adapter.getSelectedItems().isEmpty()) {
|
||||
count = (int) adapter.getSelectedItems()
|
||||
.stream()
|
||||
.map(MultiselectPart::getConversationMessage)
|
||||
.distinct()
|
||||
.count();
|
||||
}
|
||||
|
||||
return String.valueOf(adapter.getSelectedItems()
|
||||
.stream()
|
||||
.map(MultiselectPart::getConversationMessage)
|
||||
.distinct()
|
||||
.count());
|
||||
return requireContext().getResources().getQuantityString(R.plurals.conversation_context__s_selected, count, count);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -1227,6 +1307,7 @@ 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,
|
||||
|
@ -1322,7 +1403,7 @@ public class ConversationFragment extends LoggingFragment implements Multiselect
|
|||
if (getListAdapter().getSelectedItems().size() == 0) {
|
||||
actionMode.finish();
|
||||
} else {
|
||||
setCorrectActionModeMenuVisibility(actionMode.getMenu());
|
||||
setCorrectActionModeMenuVisibility();
|
||||
actionMode.setTitle(calculateSelectedItemCount());
|
||||
}
|
||||
}
|
||||
|
@ -1806,12 +1887,9 @@ 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(menu);
|
||||
setCorrectActionModeMenuVisibility();
|
||||
listener.onMessageActionToolbarOpened();
|
||||
return true;
|
||||
}
|
||||
|
@ -1825,44 +1903,12 @@ 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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -108,8 +108,10 @@ class MultiselectItemDecoration(
|
|||
override fun getItemOffsets(outRect: Rect, view: View, parent: RecyclerView, state: RecyclerView.State) {
|
||||
val currentSelection = getCurrentSelection(parent)
|
||||
if (selectedParts.isEmpty() && currentSelection.isNotEmpty()) {
|
||||
val wasRunning = enterExitAnimation?.isRunning ?: false
|
||||
enterExitAnimation?.end()
|
||||
enterExitAnimation = ValueAnimator.ofFloat(enterExitAnimation?.animatedFraction ?: 0f, 1f).apply {
|
||||
val startValue = if (wasRunning) enterExitAnimation?.animatedFraction else 0f
|
||||
enterExitAnimation = ValueAnimator.ofFloat(startValue ?: 0f, 1f).apply {
|
||||
duration = 150L
|
||||
start()
|
||||
}
|
||||
|
@ -142,7 +144,10 @@ class MultiselectItemDecoration(
|
|||
|
||||
if (adapter.selectedItems.isEmpty()) {
|
||||
drawFocusShadeUnderIfNecessary(canvas, parent)
|
||||
return
|
||||
|
||||
if (enterExitAnimation == null || !isInitialAnimation()) {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
shadePaint.color = when {
|
||||
|
@ -189,7 +194,9 @@ class MultiselectItemDecoration(
|
|||
canvas.restore()
|
||||
}
|
||||
|
||||
drawChecks(parent, canvas, adapter)
|
||||
if (adapter.selectedItems.isNotEmpty()) {
|
||||
drawChecks(parent, canvas, adapter)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -312,7 +319,8 @@ class MultiselectItemDecoration(
|
|||
val adapter = parent.adapter as ConversationAdapter
|
||||
val isLtr = ViewUtil.isLtr(child)
|
||||
|
||||
if (adapter.selectedItems.isNotEmpty() && child is Multiselectable) {
|
||||
val isAnimatingSelection = enterExitAnimation != null && isInitialAnimation()
|
||||
if ((isAnimatingSelection || adapter.selectedItems.isNotEmpty()) && child is Multiselectable) {
|
||||
val target = child.getHorizontalTranslationTarget()
|
||||
|
||||
if (target != null) {
|
||||
|
@ -323,7 +331,7 @@ class MultiselectItemDecoration(
|
|||
}
|
||||
|
||||
val translation: Float = if (isInitialAnimation()) {
|
||||
max(0, gutter - start) * (enterExitAnimation?.animatedFraction ?: 1f)
|
||||
max(0, gutter - start) * (enterExitAnimation?.animatedValue as Float? ?: 1f)
|
||||
} else {
|
||||
max(0, gutter - start).toFloat()
|
||||
}
|
||||
|
|
5
app/src/main/res/drawable-ldrtl/ic_forward_24_tinted.xml
Normal file
5
app/src/main/res/drawable-ldrtl/ic_forward_24_tinted.xml
Normal file
|
@ -0,0 +1,5 @@
|
|||
<vector android:height="24dp"
|
||||
android:viewportHeight="24" android:viewportWidth="24"
|
||||
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="@color/signal_icon_tint_primary" android:pathData="M9.5,5.621v3.7l1.309,0.169a10.932,10.932 0,0 1,9.364 7.253c0.161,0.406 0.8,1.756 0.8,1.756A19.408,19.408 0,0 0,19.5 17.2,17.455 17.455,0 0,0 11.115,14.5L9.5,14.38v4L3.121,12 9.5,5.621m1.137,-3.037a0.758,0.758 0,0 0,-0.491 0.27L1.354,11.646a0.5,0.5 0,0 0,0 0.708l8.792,8.792a0.758,0.758 0,0 0,0.491 0.27c0.219,0 0.363,-0.217 0.363,-0.623V16a14.706,14.706 0,0 1,10.905 5.426c0.282,0.355 0.514,0.529 0.677,0.529 0.214,0 0.3,-0.3 0.222,-0.9C21.822,14.051 18.264,8.934 11,8V3.207c0,-0.406 -0.144,-0.623 -0.363,-0.623Z"/>
|
||||
</vector>
|
9
app/src/main/res/drawable-ldrtl/ic_reply_24_tinted.xml
Normal file
9
app/src/main/res/drawable-ldrtl/ic_reply_24_tinted.xml
Normal file
|
@ -0,0 +1,9 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="@color/signal_icon_tint_primary"
|
||||
android:pathData="M12.91,3.91h0m1.71,2.16V9.32l-1.31,0.17A11,11 0,0 0,3.84 17c-0.12,0.33 -0.8,1.59 -0.8,1.59s1,-1 1.3,-1.22A17.36,17.36 0,0 1,13 14.5l1.62,-0.12v3.48l-0.06,0.81L15,18 21,12 14.9,5.9l-0.34,-0.54ZM13.48,2.58a0.76,0.76 0,0 1,0.49 0.27l8.79,8.8a0.48,0.48 0,0 1,0 0.7L14,21.15a0.76,0.76 0,0 1,-0.49 0.27c-0.22,0 -0.36,-0.22 -0.36,-0.63V16c-5,0.39 -8.83,2.48 -11.37,6 -0.14,0.2 -0.27,0.29 -0.37,0.29s-0.2,-0.17 -0.16,-0.5C2,14.43 5.59,9 13.12,8V3.21c0,-0.41 0.14,-0.63 0.36,-0.63Z"/>
|
||||
</vector>
|
9
app/src/main/res/drawable-night/ic_delete_tinted_24.xml
Normal file
9
app/src/main/res/drawable-night/ic_delete_tinted_24.xml
Normal file
|
@ -0,0 +1,9 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:pathData="M16.38,4.5C16.1558,3.5058 15.6,2.6174 14.804,1.981C14.008,1.3445 13.0192,0.9978 12,0.9978C10.9808,0.9978 9.992,1.3445 9.196,1.981C8.4,2.6174 7.8442,3.5058 7.62,4.5H2V6H3.5L4.86,20C4.9216,20.5507 5.1842,21.0593 5.5975,21.4284C6.0109,21.7974 6.5459,22.001 7.1,22H16.9C17.4541,22.001 17.9891,21.7974 18.4025,21.4284C18.8158,21.0593 19.0784,20.5507 19.14,20L20.5,6H22V4.5H16.38ZM12,2.5C12.6189,2.5017 13.2222,2.6949 13.7271,3.0529C14.2319,3.411 14.6137,3.9165 14.82,4.5H9.18C9.3863,3.9165 9.7681,3.411 10.2729,3.0529C10.7778,2.6949 11.3811,2.5017 12,2.5V2.5ZM8,18L7.5,8H9L9.5,18H8ZM12.75,18H11.25V8H12.75V18ZM16,18H14.5L15,8H16.5L16,18Z"
|
||||
android:fillColor="@color/signal_icon_tint_primary"/>
|
||||
</vector>
|
9
app/src/main/res/drawable/ic_delete_tinted_24.xml
Normal file
9
app/src/main/res/drawable/ic_delete_tinted_24.xml
Normal file
|
@ -0,0 +1,9 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:pathData="M22,4.5H16.35C16.1356,3.5056 15.5869,2.6147 14.7954,1.9756C14.0038,1.3366 13.0173,0.9881 12,0.9881C10.9827,0.9881 9.9962,1.3366 9.2046,1.9756C8.4131,2.6147 7.8644,3.5056 7.65,4.5H2V6H3.5L4.86,20C4.9216,20.5507 5.1842,21.0593 5.5975,21.4284C6.0109,21.7974 6.5459,22.001 7.1,22H16.9C17.4541,22.001 17.9891,21.7974 18.4025,21.4284C18.8158,21.0593 19.0784,20.5507 19.14,20L20.5,6H22V4.5ZM12,2.5C12.6189,2.5017 13.2222,2.6949 13.7271,3.0529C14.2319,3.411 14.6137,3.9165 14.82,4.5H9.18C9.3863,3.9165 9.7681,3.411 10.2729,3.0529C10.7778,2.6949 11.3811,2.5017 12,2.5V2.5ZM17.65,19.83C17.6281,20.0139 17.5398,20.1834 17.4017,20.3068C17.2636,20.4302 17.0852,20.4989 16.9,20.5H7.1C6.9148,20.4989 6.7364,20.4302 6.5983,20.3068C6.4602,20.1834 6.3719,20.0139 6.35,19.83L5,6H19L17.65,19.83ZM11.25,18V8H12.75V18H11.25ZM14.5,18L15,8H16.5L16,18H14.5ZM8,18L7.5,8H9L9.5,18H8Z"
|
||||
android:fillColor="@color/signal_icon_tint_primary"/>
|
||||
</vector>
|
10
app/src/main/res/drawable/ic_forward_24_tinted.xml
Normal file
10
app/src/main/res/drawable/ic_forward_24_tinted.xml
Normal file
|
@ -0,0 +1,10 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:autoMirrored="true"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="@color/signal_icon_tint_primary"
|
||||
android:pathData="M12.91,3.91h0m1.71,2.16V9.32l-1.31,0.17A11,11 0,0 0,3.84 17c-0.12,0.33 -0.8,1.59 -0.8,1.59s1,-1 1.3,-1.22A17.36,17.36 0,0 1,13 14.5l1.62,-0.12v3.48l-0.06,0.81L15,18 21,12 14.9,5.9l-0.34,-0.54ZM13.48,2.58a0.76,0.76 0,0 1,0.49 0.27l8.79,8.8a0.48,0.48 0,0 1,0 0.7L14,21.15a0.76,0.76 0,0 1,-0.49 0.27c-0.22,0 -0.36,-0.22 -0.36,-0.63V16c-5,0.39 -8.83,2.48 -11.37,6 -0.14,0.2 -0.27,0.29 -0.37,0.29s-0.2,-0.17 -0.16,-0.5C2,14.43 5.59,9 13.12,8V3.21c0,-0.41 0.14,-0.63 0.36,-0.63Z"/>
|
||||
</vector>
|
5
app/src/main/res/drawable/ic_reply_24_tinted.xml
Normal file
5
app/src/main/res/drawable/ic_reply_24_tinted.xml
Normal file
|
@ -0,0 +1,5 @@
|
|||
<vector android:autoMirrored="true" android:height="24dp"
|
||||
android:viewportHeight="24" android:viewportWidth="24"
|
||||
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="@color/signal_icon_tint_primary" android:pathData="M9.5,5.621v3.7l1.309,0.169a10.932,10.932 0,0 1,9.364 7.253c0.161,0.406 0.8,1.756 0.8,1.756A19.408,19.408 0,0 0,19.5 17.2,17.455 17.455,0 0,0 11.115,14.5L9.5,14.38v4L3.121,12 9.5,5.621m1.137,-3.037a0.758,0.758 0,0 0,-0.491 0.27L1.354,11.646a0.5,0.5 0,0 0,0 0.708l8.792,8.792a0.758,0.758 0,0 0,0.491 0.27c0.219,0 0.363,-0.217 0.363,-0.623V16a14.706,14.706 0,0 1,10.905 5.426c0.282,0.355 0.514,0.529 0.677,0.529 0.214,0 0.3,-0.3 0.222,-0.9C21.822,14.051 18.264,8.934 11,8V3.207c0,-0.406 -0.144,-0.623 -0.363,-0.623Z"/>
|
||||
</vector>
|
|
@ -49,7 +49,7 @@
|
|||
android:layout_height="0dp"
|
||||
android:layout_weight="1">
|
||||
|
||||
<FrameLayout
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||
android:id="@+id/fragment_content"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
android:cacheColorHint="@color/signal_background_primary"
|
||||
android:clipChildren="false"
|
||||
android:clipToPadding="false"
|
||||
android:paddingBottom="2dp"
|
||||
android:paddingBottom="@dimen/conversation_bottom_padding"
|
||||
android:scrollbars="vertical"
|
||||
android:overScrollMode="ifContentScrolls"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
@ -88,4 +88,15 @@
|
|||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent" />
|
||||
|
||||
<org.thoughtcrime.securesms.components.menu.SignalBottomActionBar
|
||||
android:id="@+id/conversation_bottom_action_bar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="16dp"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
|
|
@ -1,46 +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/conversation_context__menu_message_details"
|
||||
android:id="@+id/menu_context_details"
|
||||
android:icon="@drawable/ic_info_white_24"
|
||||
app:iconTint="@color/signal_icon_tint_primary"
|
||||
app:showAsAction="always" />
|
||||
|
||||
<item android:title="@string/conversation_context__menu_delete_message"
|
||||
android:id="@+id/menu_context_delete_message"
|
||||
android:icon="@drawable/ic_trash_24"
|
||||
app:iconTint="@color/signal_icon_tint_primary"
|
||||
app:showAsAction="always" />
|
||||
|
||||
<item android:title="@string/conversation_context__menu_copy_text"
|
||||
android:id="@+id/menu_context_copy"
|
||||
android:icon="@drawable/ic_copy_24"
|
||||
app:iconTint="@color/signal_icon_tint_primary"
|
||||
app:showAsAction="always" />
|
||||
|
||||
<item android:title="@string/conversation_context__menu_reply_to_message"
|
||||
android:id="@+id/menu_context_reply"
|
||||
android:visible="true"
|
||||
android:icon="@drawable/ic_reply_24"
|
||||
app:iconTint="@color/signal_icon_tint_primary"
|
||||
app:showAsAction="always" />
|
||||
|
||||
<item android:title="@string/conversation_context__menu_resend_message"
|
||||
android:id="@+id/menu_context_resend"
|
||||
android:visible="false"
|
||||
app:showAsAction="never" />
|
||||
|
||||
<item android:title="@string/conversation_context_image__save_attachment"
|
||||
android:id="@+id/menu_context_save_attachment"
|
||||
android:visible="false"
|
||||
android:icon="@drawable/ic_save_24"
|
||||
app:iconTint="@color/signal_icon_tint_primary"
|
||||
app:showAsAction="always" />
|
||||
|
||||
<item android:title="@string/conversation_context__menu_forward_message"
|
||||
android:id="@+id/menu_context_forward"
|
||||
android:icon="@drawable/ic_forward_24"
|
||||
app:iconTint="@color/signal_icon_tint_primary"
|
||||
app:showAsAction="always" />
|
||||
|
||||
</menu>
|
|
@ -69,6 +69,7 @@
|
|||
|
||||
<dimen name="thumbnail_default_radius">4dp</dimen>
|
||||
|
||||
<dimen name="conversation_bottom_padding">2dp</dimen>
|
||||
<dimen name="conversation_compose_height">40dp</dimen>
|
||||
<dimen name="conversation_individual_right_gutter">16dp</dimen>
|
||||
<dimen name="conversation_individual_left_gutter">16dp</dimen>
|
||||
|
|
|
@ -2785,13 +2785,22 @@
|
|||
<string name="conversation_context__menu_forward_message">Forward</string>
|
||||
<!-- Button to retry sending a message -->
|
||||
<string name="conversation_context__menu_resend_message">Resend message</string>
|
||||
<string name="conversation_context__menu_reply_to_message">Reply to message</string>
|
||||
<!-- Button to reply to a message -->
|
||||
<string name="conversation_context__menu_reply_to_message">Reply</string>
|
||||
|
||||
<!-- conversation_context_reacction -->
|
||||
<!-- conversation_context_reaction -->
|
||||
<!-- Button to select a message and enter selection mode -->
|
||||
<string name="conversation_context__reaction_multi_select">Select multiple</string>
|
||||
|
||||
<!-- Heading which shows how many messages are currently selected -->
|
||||
<plurals name="conversation_context__s_selected">
|
||||
<item quantity="one">%d selected</item>
|
||||
<item quantity="other">%d selected</item>
|
||||
</plurals>
|
||||
|
||||
<!-- conversation_context_image -->
|
||||
<string name="conversation_context_image__save_attachment">Save attachment</string>
|
||||
<!-- Button to save a message attachment (image, file etc.) -->
|
||||
<string name="conversation_context_image__save_attachment">Save</string>
|
||||
|
||||
<!-- conversation_expiring_off -->
|
||||
<string name="conversation_expiring_off__disappearing_messages">Disappearing messages</string>
|
||||
|
|
Loading…
Add table
Reference in a new issue