mirror of
https://github.com/signalapp/Signal-Android.git
synced 2025-12-24 13:08:46 +00:00
Reimplement conversation action mode to not use system actionmode.
This commit is contained in:
committed by
jeffrey-signal
parent
b9e0d9978b
commit
e0d56bfadf
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright 2025 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package org.thoughtcrime.securesms.components.compose
|
||||
|
||||
import androidx.compose.foundation.layout.WindowInsets
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TopAppBar
|
||||
import androidx.compose.material3.TopAppBarDefaults
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.res.vectorResource
|
||||
import androidx.compose.ui.tooling.preview.PreviewLightDark
|
||||
import org.signal.core.ui.compose.IconButtons
|
||||
import org.signal.core.ui.compose.Previews
|
||||
import org.thoughtcrime.securesms.R
|
||||
|
||||
/**
|
||||
* A consistent ActionMode top-bar for dealing with multiselect scenarios.
|
||||
*/
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun ActionModeTopBar(
|
||||
title: String,
|
||||
onCloseClick: () -> Unit,
|
||||
toolbarColor: Color? = null,
|
||||
windowInsets: WindowInsets = TopAppBarDefaults.windowInsets
|
||||
) {
|
||||
TopAppBar(
|
||||
colors = TopAppBarDefaults.topAppBarColors(
|
||||
containerColor = toolbarColor ?: MaterialTheme.colorScheme.surface
|
||||
),
|
||||
navigationIcon = {
|
||||
IconButtons.IconButton(onClick = onCloseClick) {
|
||||
Icon(
|
||||
imageVector = ImageVector.vectorResource(R.drawable.symbol_x_24),
|
||||
contentDescription = stringResource(R.string.CallScreenTopBar__go_back)
|
||||
)
|
||||
}
|
||||
},
|
||||
title = {
|
||||
Text(text = title)
|
||||
},
|
||||
windowInsets = windowInsets
|
||||
)
|
||||
}
|
||||
|
||||
@PreviewLightDark
|
||||
@Composable
|
||||
fun ActionModeTopBarPreview() {
|
||||
Previews.Preview {
|
||||
ActionModeTopBar(
|
||||
title = "1 selected",
|
||||
onCloseClick = {}
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright 2025 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package org.thoughtcrime.securesms.components.compose
|
||||
|
||||
import android.content.Context
|
||||
import android.util.AttributeSet
|
||||
import androidx.compose.foundation.layout.WindowInsets
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.platform.AbstractComposeView
|
||||
import org.signal.core.ui.compose.theme.SignalTheme
|
||||
import org.thoughtcrime.securesms.util.DynamicTheme
|
||||
|
||||
/**
|
||||
* A View wrapper for [ActionModeTopBar] so that we can use the same UI element in View and Compose land.
|
||||
*/
|
||||
class ActionModeTopBarView @JvmOverloads constructor(
|
||||
context: Context,
|
||||
attrs: AttributeSet? = null,
|
||||
defStyleAttr: Int = 0
|
||||
) : AbstractComposeView(context, attrs, defStyleAttr) {
|
||||
|
||||
var title by mutableStateOf("")
|
||||
var onCloseClick: () -> Unit by mutableStateOf({})
|
||||
|
||||
@Composable
|
||||
override fun Content() {
|
||||
SignalTheme(isDarkMode = DynamicTheme.isDarkTheme(context)) {
|
||||
Surface(
|
||||
color = Color.Transparent,
|
||||
contentColor = MaterialTheme.colorScheme.onSurface
|
||||
) {
|
||||
ActionModeTopBar(
|
||||
title = title,
|
||||
toolbarColor = Color.Transparent,
|
||||
onCloseClick = onCloseClick,
|
||||
windowInsets = WindowInsets()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -78,12 +78,8 @@ public final class ConversationReactionOverlay extends FrameLayout {
|
||||
private boolean downIsOurs;
|
||||
private int selected = -1;
|
||||
private int customEmojiIndex;
|
||||
private int originalStatusBarColor;
|
||||
private int originalNavigationBarColor;
|
||||
|
||||
private View dropdownAnchor;
|
||||
private View toolbarShade;
|
||||
private View inputShade;
|
||||
private View conversationItem;
|
||||
private View backgroundView;
|
||||
private ConstraintLayout foregroundView;
|
||||
@@ -121,8 +117,6 @@ public final class ConversationReactionOverlay extends FrameLayout {
|
||||
super.onFinishInflate();
|
||||
|
||||
dropdownAnchor = findViewById(R.id.dropdown_anchor);
|
||||
toolbarShade = findViewById(R.id.toolbar_shade);
|
||||
inputShade = findViewById(R.id.input_shade);
|
||||
conversationItem = findViewById(R.id.conversation_item);
|
||||
backgroundView = findViewById(R.id.conversation_reaction_scrubber_background);
|
||||
foregroundView = findViewById(R.id.conversation_reaction_scrubber_foreground);
|
||||
@@ -214,9 +208,6 @@ public final class ConversationReactionOverlay extends FrameLayout {
|
||||
@NonNull ConversationMessage conversationMessage,
|
||||
@NonNull PointF lastSeenDownPoint,
|
||||
boolean isMessageOnLeft) {
|
||||
updateToolbarShade();
|
||||
updateInputShade();
|
||||
|
||||
contextMenu = new ConversationContextMenu(dropdownAnchor, getMenuActionItems(conversationMessage));
|
||||
|
||||
conversationItem.setX(selectedConversationModel.getSnapshotMetrics().getSnapshotOffset());
|
||||
@@ -397,18 +388,6 @@ public final class ConversationReactionOverlay extends FrameLayout {
|
||||
return Math.max(reactionStartingPoint - reactionBarOffset - reactionBarHeight, spaceNeededBetweenTopOfScreenAndTopOfReactionBar);
|
||||
}
|
||||
|
||||
private void updateToolbarShade() {
|
||||
LayoutParams layoutParams = (LayoutParams) toolbarShade.getLayoutParams();
|
||||
layoutParams.height = 0;
|
||||
toolbarShade.setLayoutParams(layoutParams);
|
||||
}
|
||||
|
||||
private void updateInputShade() {
|
||||
LayoutParams layoutParams = (LayoutParams) inputShade.getLayoutParams();
|
||||
layoutParams.height = 0;
|
||||
inputShade.setLayoutParams(layoutParams);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true when the device is in a configuration where the navigation bar doesn't take up
|
||||
* space at the bottom of the screen.
|
||||
@@ -448,9 +427,6 @@ public final class ConversationReactionOverlay extends FrameLayout {
|
||||
@Override public void onAnimationEnd(Animator animation) {
|
||||
animatorSet.removeListener(this);
|
||||
|
||||
toolbarShade.setVisibility(INVISIBLE);
|
||||
inputShade.setVisibility(INVISIBLE);
|
||||
|
||||
if (onHideListener != null) {
|
||||
onHideListener.onHide();
|
||||
}
|
||||
@@ -872,22 +848,6 @@ public final class ConversationReactionOverlay extends FrameLayout {
|
||||
itemYAnim.setDuration(duration);
|
||||
animators.add(itemYAnim);
|
||||
|
||||
if (activity != null) {
|
||||
ValueAnimator statusBarAnim = ValueAnimator.ofArgb(activity.getWindow().getStatusBarColor(), originalStatusBarColor);
|
||||
statusBarAnim.setDuration(duration);
|
||||
statusBarAnim.addUpdateListener(animation -> {
|
||||
WindowUtil.setStatusBarColor(activity.getWindow(), (int) animation.getAnimatedValue());
|
||||
});
|
||||
animators.add(statusBarAnim);
|
||||
|
||||
ValueAnimator navigationBarAnim = ValueAnimator.ofArgb(activity.getWindow().getStatusBarColor(), originalNavigationBarColor);
|
||||
navigationBarAnim.setDuration(duration);
|
||||
navigationBarAnim.addUpdateListener(animation -> {
|
||||
WindowUtil.setNavigationBarColor(activity, (int) animation.getAnimatedValue());
|
||||
});
|
||||
animators.add(navigationBarAnim);
|
||||
}
|
||||
|
||||
return animators;
|
||||
}
|
||||
|
||||
|
||||
@@ -45,8 +45,6 @@ import androidx.activity.OnBackPressedCallback
|
||||
import androidx.activity.result.ActivityResultLauncher
|
||||
import androidx.annotation.MainThread
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.appcompat.view.ActionMode
|
||||
import androidx.appcompat.widget.SearchView
|
||||
import androidx.appcompat.widget.Toolbar
|
||||
import androidx.core.app.ActivityOptionsCompat
|
||||
@@ -135,6 +133,7 @@ import org.thoughtcrime.securesms.components.InsetAwareConstraintLayout
|
||||
import org.thoughtcrime.securesms.components.ScrollToPositionDelegate
|
||||
import org.thoughtcrime.securesms.components.SendButton
|
||||
import org.thoughtcrime.securesms.components.ViewBinderDelegate
|
||||
import org.thoughtcrime.securesms.components.compose.ActionModeTopBarView
|
||||
import org.thoughtcrime.securesms.components.compose.DeleteSyncEducationDialog
|
||||
import org.thoughtcrime.securesms.components.emoji.EmojiEventListener
|
||||
import org.thoughtcrime.securesms.components.emoji.MediaKeyboard
|
||||
@@ -535,7 +534,6 @@ class ConversationFragment :
|
||||
private lateinit var optionsMenuCallback: ConversationOptionsMenuCallback
|
||||
|
||||
private var animationsAllowed = false
|
||||
private var actionMode: ActionMode? = null
|
||||
private var pinnedShortcutReceiver: BroadcastReceiver? = null
|
||||
private var searchMenuItem: MenuItem? = null
|
||||
|
||||
@@ -562,10 +560,6 @@ class ConversationFragment :
|
||||
|
||||
private val motionEventRelay: MotionEventRelay by viewModels(ownerProducer = { requireActivity() })
|
||||
|
||||
private val actionModeCallback by lazy {
|
||||
ActionModeCallback()
|
||||
}
|
||||
|
||||
private val container: InputAwareConstraintLayout
|
||||
get() = requireView() as InputAwareConstraintLayout
|
||||
|
||||
@@ -587,6 +581,9 @@ class ConversationFragment :
|
||||
private val searchNav: ConversationSearchBottomBar
|
||||
get() = binding.conversationSearchBottomBar.root
|
||||
|
||||
private val actionModeTopBarView: ActionModeTopBarView
|
||||
get() = binding.actionModeTopBar
|
||||
|
||||
private val scheduledMessagesStub: Stub<View> by lazy { Stub(binding.scheduledMessagesStub) }
|
||||
|
||||
private val reactionDelegate: ConversationReactionDelegate by lazy(LazyThreadSafetyMode.NONE) {
|
||||
@@ -929,13 +926,52 @@ class ConversationFragment :
|
||||
}
|
||||
|
||||
override fun onFinishForwardAction() {
|
||||
actionMode?.finish()
|
||||
finishActionMode()
|
||||
}
|
||||
|
||||
override fun onDismissForwardSheet() = Unit
|
||||
|
||||
//endregion
|
||||
|
||||
private fun startActionMode() {
|
||||
actionModeTopBarView.isVisible = true
|
||||
actionModeTopBarView.onCloseClick = this::finishActionMode
|
||||
actionModeTopBarView.title = calculateSelectedItemCount()
|
||||
|
||||
searchMenuItem?.collapseActionView()
|
||||
binding.toolbar.isInvisible = true
|
||||
if (scheduledMessagesStub.isVisible) {
|
||||
reShowScheduleMessagesBar = true
|
||||
scheduledMessagesStub.visibility = View.GONE
|
||||
}
|
||||
|
||||
setCorrectActionModeMenuVisibility()
|
||||
binding.conversationItemRecycler.invalidateItemDecorations()
|
||||
}
|
||||
|
||||
private fun setActionModeTitle(title: String) {
|
||||
actionModeTopBarView.title = title
|
||||
}
|
||||
|
||||
private fun isActionModeStarted(): Boolean {
|
||||
return actionModeTopBarView.isVisible
|
||||
}
|
||||
|
||||
private fun finishActionMode() {
|
||||
actionModeTopBarView.isVisible = false
|
||||
|
||||
adapter.clearSelection()
|
||||
setBottomActionBarVisibility(false)
|
||||
|
||||
binding.toolbar.isInvisible = false
|
||||
if (reShowScheduleMessagesBar) {
|
||||
scheduledMessagesStub.visibility = View.VISIBLE
|
||||
reShowScheduleMessagesBar = false
|
||||
}
|
||||
|
||||
binding.conversationItemRecycler.invalidateItemDecorations()
|
||||
}
|
||||
|
||||
private fun createGroupSubtitleString(members: List<Recipient>): String {
|
||||
return members.joinToString(", ") { r -> if (r.isSelf) getString(R.string.ConversationTitleView_you) else r.getDisplayName(requireContext()) }
|
||||
}
|
||||
@@ -2164,13 +2200,11 @@ class ConversationFragment :
|
||||
private fun setCorrectActionModeMenuVisibility() {
|
||||
val selectedParts = adapter.selectedItems
|
||||
|
||||
if (actionMode != null && selectedParts.isEmpty()) {
|
||||
actionMode?.finish()
|
||||
if (isActionModeStarted() && selectedParts.isEmpty()) {
|
||||
finishActionMode()
|
||||
return
|
||||
}
|
||||
|
||||
setBottomActionBarVisibility(true)
|
||||
|
||||
val recipient = viewModel.recipientSnapshot ?: return
|
||||
val menuState = MenuState.getMenuState(
|
||||
recipient,
|
||||
@@ -2186,7 +2220,7 @@ class ConversationFragment :
|
||||
ActionItem(R.drawable.symbol_reply_24, resources.getString(R.string.conversation_selection__menu_reply)) {
|
||||
maybeShowSwipeToReplyTooltip()
|
||||
handleReplyToMessage(getSelectedConversationMessage())
|
||||
actionMode?.finish()
|
||||
finishActionMode()
|
||||
}
|
||||
)
|
||||
}
|
||||
@@ -2195,7 +2229,7 @@ class ConversationFragment :
|
||||
items.add(
|
||||
ActionItem(R.drawable.symbol_edit_24, resources.getString(R.string.conversation_selection__menu_edit)) {
|
||||
handleEditMessage(getSelectedConversationMessage())
|
||||
actionMode?.finish()
|
||||
finishActionMode()
|
||||
}
|
||||
)
|
||||
}
|
||||
@@ -2212,7 +2246,7 @@ class ConversationFragment :
|
||||
items.add(
|
||||
ActionItem(R.drawable.symbol_save_android_24, getResources().getString(R.string.conversation_selection__menu_save)) {
|
||||
handleSaveAttachment(getSelectedConversationMessage().messageRecord as MmsMessageRecord)
|
||||
actionMode?.finish()
|
||||
finishActionMode()
|
||||
}
|
||||
)
|
||||
}
|
||||
@@ -2221,7 +2255,7 @@ class ConversationFragment :
|
||||
items.add(
|
||||
ActionItem(R.drawable.symbol_copy_android_24, getResources().getString(R.string.conversation_selection__menu_copy)) {
|
||||
handleCopyMessage(selectedParts)
|
||||
actionMode?.finish()
|
||||
finishActionMode()
|
||||
}
|
||||
)
|
||||
}
|
||||
@@ -2230,7 +2264,7 @@ class ConversationFragment :
|
||||
items.add(
|
||||
ActionItem(R.drawable.symbol_info_24, getResources().getString(R.string.conversation_selection__menu_message_details)) {
|
||||
handleDisplayDetails(getSelectedConversationMessage())
|
||||
actionMode?.finish()
|
||||
finishActionMode()
|
||||
}
|
||||
)
|
||||
}
|
||||
@@ -2239,12 +2273,15 @@ class ConversationFragment :
|
||||
items.add(
|
||||
ActionItem(R.drawable.symbol_trash_24, getResources().getString(R.string.conversation_selection__menu_delete)) {
|
||||
handleDeleteMessages(selectedParts)
|
||||
actionMode?.finish()
|
||||
finishActionMode()
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
bottomActionBar.setItems(items)
|
||||
bottomActionBar.doAfterNextLayout {
|
||||
setBottomActionBarVisibility(true)
|
||||
}
|
||||
}
|
||||
|
||||
private fun setBottomActionBarVisibility(isVisible: Boolean) {
|
||||
@@ -2266,12 +2303,13 @@ class ConversationFragment :
|
||||
|
||||
bottomActionBar.viewTreeObserver.addOnPreDrawListener(object : ViewTreeObserver.OnPreDrawListener {
|
||||
override fun onPreDraw(): Boolean {
|
||||
if (bottomActionBar.height == 0 && bottomActionBar.visible) {
|
||||
if (bottomActionBar.measuredHeight == 0 && bottomActionBar.visible) {
|
||||
return false
|
||||
}
|
||||
|
||||
bottomActionBar.viewTreeObserver.removeOnPreDrawListener(this)
|
||||
|
||||
val bottomPadding = bottomActionBar.height + ((bottomActionBar.layoutParams as? ViewGroup.MarginLayoutParams)?.bottomMargin ?: 18.dp)
|
||||
val bottomPadding = bottomActionBar.measuredHeight + ((bottomActionBar.layoutParams as? ViewGroup.MarginLayoutParams)?.bottomMargin ?: 18.dp)
|
||||
ViewUtil.setPaddingBottom(binding.conversationItemRecycler, bottomPadding)
|
||||
binding.conversationItemRecycler.scrollBy(0, -(bottomPadding - additionalScrollOffset))
|
||||
animationsAllowed = true
|
||||
@@ -2540,8 +2578,7 @@ class ConversationFragment :
|
||||
private fun handleEnterMultiselect(conversationMessage: ConversationMessage) {
|
||||
val parts = conversationMessage.multiselectCollection.toSet()
|
||||
parts.forEach { adapter.toggleSelection(it) }
|
||||
binding.conversationItemRecycler.invalidateItemDecorations()
|
||||
actionMode = (requireActivity() as AppCompatActivity).startSupportActionMode(actionModeCallback)
|
||||
startActionMode()
|
||||
}
|
||||
|
||||
private fun handleViewPaymentDetails(conversationMessage: ConversationMessage) {
|
||||
@@ -2621,7 +2658,7 @@ class ConversationFragment :
|
||||
override fun isSwipeAvailable(conversationMessage: ConversationMessage): Boolean {
|
||||
val recipient = viewModel.recipientSnapshot ?: return false
|
||||
|
||||
return actionMode == null &&
|
||||
return !isActionModeStarted() &&
|
||||
MenuState.canReplyToMessage(
|
||||
recipient,
|
||||
MenuState.isActionMessage(conversationMessage.messageRecord),
|
||||
@@ -2833,7 +2870,7 @@ class ConversationFragment :
|
||||
}
|
||||
|
||||
override fun onItemRangeRemoved(positionStart: Int, itemCount: Int) {
|
||||
if (actionMode == null) {
|
||||
if (!isActionModeStarted()) {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -2845,9 +2882,9 @@ class ConversationFragment :
|
||||
adapter.removeFromSelection(expired)
|
||||
|
||||
if (adapter.selectedItems.isEmpty()) {
|
||||
actionMode?.finish()
|
||||
finishActionMode()
|
||||
} else {
|
||||
actionMode?.setTitle(calculateSelectedItemCount())
|
||||
setActionModeTitle(calculateSelectedItemCount())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3311,22 +3348,22 @@ class ConversationFragment :
|
||||
}
|
||||
|
||||
override fun onItemClick(item: MultiselectPart) {
|
||||
if (actionMode != null) {
|
||||
if (isActionModeStarted()) {
|
||||
adapter.toggleSelection(item)
|
||||
binding.conversationItemRecycler.invalidateItemDecorations()
|
||||
|
||||
if (adapter.selectedItems.isEmpty()) {
|
||||
actionMode?.finish()
|
||||
finishActionMode()
|
||||
} else {
|
||||
setCorrectActionModeMenuVisibility()
|
||||
actionMode?.title = calculateSelectedItemCount()
|
||||
setActionModeTitle(calculateSelectedItemCount())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onItemLongClick(itemView: View, item: MultiselectPart) {
|
||||
Log.d(TAG, "onItemLongClick")
|
||||
if (actionMode != null) {
|
||||
if (isActionModeStarted()) {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -3466,9 +3503,7 @@ class ConversationFragment :
|
||||
} else {
|
||||
clearFocusedItem()
|
||||
adapter.toggleSelection(item)
|
||||
binding.conversationItemRecycler.invalidateItemDecorations()
|
||||
|
||||
actionMode = (requireActivity() as AppCompatActivity).startSupportActionMode(actionModeCallback)
|
||||
startActionMode()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3838,40 +3873,6 @@ class ConversationFragment :
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inner class ActionModeCallback : ActionMode.Callback {
|
||||
override fun onCreateActionMode(mode: ActionMode, menu: Menu): Boolean {
|
||||
mode.title = calculateSelectedItemCount()
|
||||
|
||||
searchMenuItem?.collapseActionView()
|
||||
binding.toolbar.isInvisible = true
|
||||
if (scheduledMessagesStub.isVisible) {
|
||||
reShowScheduleMessagesBar = true
|
||||
scheduledMessagesStub.visibility = View.GONE
|
||||
}
|
||||
|
||||
setCorrectActionModeMenuVisibility()
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onPrepareActionMode(mode: ActionMode, menu: Menu): Boolean = false
|
||||
|
||||
override fun onActionItemClicked(mode: ActionMode, item: MenuItem): Boolean = false
|
||||
|
||||
override fun onDestroyActionMode(mode: ActionMode) {
|
||||
adapter.clearSelection()
|
||||
setBottomActionBarVisibility(false)
|
||||
|
||||
binding.toolbar.isInvisible = false
|
||||
if (reShowScheduleMessagesBar) {
|
||||
scheduledMessagesStub.visibility = View.VISIBLE
|
||||
reShowScheduleMessagesBar = false
|
||||
}
|
||||
|
||||
binding.conversationItemRecycler.invalidateItemDecorations()
|
||||
actionMode = null
|
||||
}
|
||||
}
|
||||
// endregion Conversation Callbacks
|
||||
|
||||
//region Activity Results Callbacks
|
||||
|
||||
@@ -61,6 +61,7 @@ import androidx.compose.ui.layout.positionInWindow
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.res.dimensionResource
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.pluralStringResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.res.vectorResource
|
||||
import androidx.compose.ui.semantics.contentDescription
|
||||
@@ -76,9 +77,9 @@ import org.signal.core.ui.compose.circularReveal
|
||||
import org.thoughtcrime.securesms.R
|
||||
import org.thoughtcrime.securesms.avatar.AvatarImage
|
||||
import org.thoughtcrime.securesms.calls.log.CallLogFilter
|
||||
import org.thoughtcrime.securesms.components.compose.ActionModeTopBar
|
||||
import org.thoughtcrime.securesms.components.settings.app.subscription.BadgeImageSmall
|
||||
import org.thoughtcrime.securesms.conversationlist.model.ConversationFilter
|
||||
import org.thoughtcrime.securesms.dependencies.GooglePlayBillingDependencies.context
|
||||
import org.thoughtcrime.securesms.recipients.Recipient
|
||||
import org.thoughtcrime.securesms.recipients.rememberRecipientField
|
||||
|
||||
@@ -226,23 +227,10 @@ private fun ActionModeToolbar(
|
||||
state: MainToolbarState,
|
||||
callback: MainToolbarCallback
|
||||
) {
|
||||
TopAppBar(
|
||||
colors = TopAppBarDefaults.topAppBarColors(
|
||||
containerColor = state.toolbarColor ?: MaterialTheme.colorScheme.surface
|
||||
),
|
||||
navigationIcon = {
|
||||
IconButtons.IconButton(onClick = {
|
||||
callback.onCloseActionModeClick()
|
||||
}) {
|
||||
Icon(
|
||||
imageVector = ImageVector.vectorResource(R.drawable.symbol_x_24),
|
||||
contentDescription = stringResource(R.string.CallScreenTopBar__go_back)
|
||||
)
|
||||
}
|
||||
},
|
||||
title = {
|
||||
Text(text = context.resources.getQuantityString(R.plurals.ConversationListFragment_s_selected, state.actionModeCount, state.actionModeCount))
|
||||
}
|
||||
ActionModeTopBar(
|
||||
title = pluralStringResource(R.plurals.ConversationListFragment_s_selected, state.actionModeCount, state.actionModeCount),
|
||||
onCloseClick = callback::onCloseActionModeClick,
|
||||
toolbarColor = state.toolbarColor
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -21,21 +21,6 @@
|
||||
android:layout_gravity="left"
|
||||
tools:ignore="RtlHardcoded" />
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/toolbar_shade"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?actionBarSize"
|
||||
android:background="@color/reactions_screen_light_shade_color"
|
||||
android:foreground="@color/reactions_screen_dark_shade_color" />
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/input_shade"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="48dp"
|
||||
android:layout_gravity="bottom"
|
||||
android:background="@color/reactions_screen_light_shade_color"
|
||||
android:foreground="@color/reactions_screen_dark_shade_color" />
|
||||
|
||||
<View
|
||||
android:id="@+id/conversation_item"
|
||||
android:layout_width="wrap_content"
|
||||
|
||||
@@ -139,6 +139,16 @@
|
||||
|
||||
</org.thoughtcrime.securesms.util.views.DarkOverflowToolbar>
|
||||
|
||||
<org.thoughtcrime.securesms.components.compose.ActionModeTopBarView
|
||||
android:id="@+id/action_mode_top_bar"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="@dimen/signal_m3_toolbar_height"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintEnd_toEndOf="@id/parent_end_guideline"
|
||||
app:layout_constraintHeight_min="@dimen/signal_m3_toolbar_height"
|
||||
app:layout_constraintStart_toStartOf="@id/parent_start_guideline"
|
||||
app:layout_constraintTop_toTopOf="@id/status_bar_guideline" />
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/conversation_banner_frame"
|
||||
android:layout_width="0dp"
|
||||
@@ -348,7 +358,7 @@
|
||||
|
||||
<org.thoughtcrime.securesms.components.menu.SignalBottomActionBar
|
||||
android:id="@+id/conversation_bottom_action_bar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="16dp"
|
||||
android:layout_marginBottom="16dp"
|
||||
|
||||
Reference in New Issue
Block a user